<?php

namespace App\Http\Controllers;

use App\Http\Resources\SchedulePlanFullResource;
use App\Http\Resources\SchedulePointResource;
use App\Models\District;
use App\Models\RequestPlanSignature;
use App\Models\User;
use App\Services\CalendarService;
use Illuminate\Http\JsonResponse;
use App\Models\Point;
use Illuminate\Support\Facades\Crypt;

//для ЭЦП
use App\Models\SchedulePlan;
use App\Models\PointPlan;
use Illuminate\Support\Facades\Auth;
use App\Models\Log;
use Illuminate\Http\Request;
use Carbon\Carbon;
use App\Http\Resources\PointPlanResource;

class SenManagerController extends Controller
{
    public function getRegionsAndManagers($id): JsonResponse
    {
        $user = User::find($id);
        $districts = $user->managedRegions()->with('districts')->get();
        $managers = User::whereHas('role', function ($query) {
            $query->where('name', 'Районный менеджер');
        })->where('is_active', true)->get()->map(function ($user) {
            $role = $user->role;
            return [
                'id' => $user->id,
                'first_name' => $user->first_name,
                'middle_name' => $user->middle_name,
                'last_name' => $user->last_name,
                'position' => $user->position,
                'role' => $role,
            ];
        });
        return response()->json(['districts' => $districts, 'managers' => $managers]);
    }

    public function proposeManagerToDistrict(Request $request): JsonResponse
    {
        $authUser = Auth::user();
        $user = User::find($request->manager_id);
        $validated = $request->validate([
            'district_id' => ['required', 'exists:districts,id'],
            'manager_id' => ['required', 'exists:users,id'],
        ]);

        $district = District::findOrFail($validated['district_id']);

        // Назначаем нового менеджера (всегда перезаписываем)
        $district->manager_id = $validated['manager_id'];
        $district->save();
        $user->userNotifications()->create([
            'title' => "Назначение менеджера на область",
            'content' => 'Вы назначены менеджером области ' . $district->name . '.',
        ]);
        Log::create([
            'model_id' => $district->id,
            'model_type' => District::class,
            'change' => 'Менеджер',
            'action' => 'На область ' . $district->name . ' назначен менеджер',
            'old_value' => '',
            'new_value' => $user->fullName(),
            'created_by' => $authUser->id,
        ]);
        return response()->json(['success' => 'Менеджер назначен.']);
    }

    public function schedulePlanInfo($id)
    {
        $plan = SchedulePlan::findOrFail($id);
        $user = $plan->senManager;

        // 1. Загружаем регионы с точками, планами и заявками
        $points = $user->managedRegions()->with([
            'districts.points.plans' => fn($q) => $q->where('is_active', true),
            'districts.points.requests',
        ])->get();

        // 2. Генерируем календарь
        $calendar = CalendarService::build($plan->year);

        // 3. Получаем подписанные заявки по месяцам
        $signed_requests = RequestPlanSignature::where('year', $plan->year)
            ->where('is_signed', true)
            ->get(['request_id', 'month', 'year']);

        // 4. Оборачиваем вручную в ресурс
        return new SchedulePlanFullResource((object)[
            'year' => $plan->year,
            'calendar' => $calendar,
            'points' => $points,
            'signed_requests' => $signed_requests,
        ]);
    }

    public function getSchedulePlanList(): JsonResponse
    {
        $schedule_plans = SchedulePlan::get();
        return response()->json(['schedule_plans' => $schedule_plans]);
    }

    public function createSchedulePlan(Request $request): JsonResponse
    {
        $year = now()->year;

        $validated = $request->validate([
            'sen_manager_id' => ['required', 'exists:users,id'],
        ]);

        // Проверка — существует ли уже план на этот год для этого менеджера
        $exists = SchedulePlan::where('year', $year)
            ->where('sen_manager_id', $validated['sen_manager_id'])
            ->exists();

        if ($exists) {
            return response()->json([
                'message' => 'План на этот год уже существует для выбранного менеджера.'
            ], 409); // HTTP 409 Conflict
        }

        SchedulePlan::create([
            'year' => $year,
            'sen_manager_id' => $validated['sen_manager_id'],
        ]);

        return response()->json(['message' => 'График успешно создан.']);
    }

    public function createSignatureSchedule($id)
    {

        $plan = SchedulePlan::find($id);
        if (!$plan) {
            return response()->json(['error' => 'Schedule plan not found'], 404);
        }

        $user = $plan->senManager;

        if (empty($user->private_key)) {
            return response()->json(['error' => 'У пользователя нет приватного ключа'], 400);
        }

        // Строим строку для хеширования
        $hashString = implode('|', [
            $plan->sen_manager_id,
            $plan->year
        ]);
        $hash = hash('sha256', $hashString);

        // Расшифровываем приватный ключ из БД
        $privateKey = Crypt::decryptString($user->private_key);

        // Подписываем хеш
        $signature = '';
        openssl_sign($hash, $signature, $privateKey, OPENSSL_ALGO_SHA256);

        $plan->update([
            'hash' => $hash,
            'signature' => base64_encode($signature),
            'signature_public_key' => $user->public_key,
        ]);

        $managers = User::whereHas('role', function ($query) {
            $query->where('name', 'Менеджер');
        })->get();

        $managers->each(function ($manager) use ($plan) {
            $manager->userNotifications()->create([
                'title' => "План график",
                'content' => "План график № " . $plan->id . " на год " . $plan->year . " подписан.",
            ]);
        });
        return response()->json([
            'message' => 'График подписан успешно',
        ]);
    }

    public function createPointPlan(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'day' => ['required', 'date'],
            'timeStart' => ['required', 'date_format:H:i'],
            'timeEnd' => ['required', 'date_format:H:i'],
            'point_id' => ['required', 'exists:points,id'],
            'schedule_id' => ['required', 'exists:schedule_point_plans,id'],
            'subgroup_manager_id' => ['required', 'exists:users,id'],
            'counter_id' => ['nullable', 'exists:counters,id'], // <-- проверяем в users
            'request_id' => ['required', 'exists:requests,id'],   // <-- новая строка
        ]);


        if (! empty($validated['counter_id'])) {
            $busyCounter = PointPlan::where('counter_id', $validated['counter_id'])
                ->whereDate('day', $validated['day'])
                ->where('timeStart', $validated['timeStart'])
                ->where('is_active', true) // Проверяем только активные работы!
                ->exists();

            if ($busyCounter) {
                return response()->json([
                    'error' => 'Этот учётчик уже назначен на другую активную работу в это же время.',
                ], 409);
            }
        }

        $schedule = SchedulePlan::findOrFail($validated['schedule_id']);
        $point = Point::findOrFail($validated['point_id']);


        if ($this->isRequestMonthSigned($validated['request_id'], $validated['day'])) {
            return response()->json([
                'error' => 'План на этот месяц по выбранной заявке уже подписан. Добавление новых работ запрещено.',
            ], 403);
        }

        $validated['subgroup_manager_id'] ??= $point->district->subgroup_manager_id;

        $pointPlan = PointPlan::create([
            'schedule_id' => $validated['schedule_id'],
            'point_id' => $validated['point_id'],
            'day' => $validated['day'],
            'timeStart' => $validated['timeStart'],
            'timeEnd' => $validated['timeEnd'],
            'subgroup_manager_id' => $validated['subgroup_manager_id'],
            'counter_id' => $validated['counter_id'] ?? null,
            'request_id' => $validated['request_id'],     // <-- сохранили
        ]);

        $user = User::find($point->district->manager_id);

        return response()->json([
            'message' => 'График точки создан.',
        ]);
    }

    private function isRequestMonthSigned(int $requestId, string $day): bool
    {
        $dt = Carbon::parse($day);
        return RequestPlanSignature::where('request_id', $requestId)
            ->where('year', $dt->year)
            ->where('month', $dt->month)
            ->exists();
    }

    public function getPointInfo($id): JsonResponse
    {
        $point = Point::with('district.region')->findOrFail($id);
        return response()->json(['point' => $point]);
    }

    public function getPointPlansList(): JsonResponse
    {
        // Получаем id доступных районов (внутри этого метода уже берётся Auth::user())
        $allowedDistrictIds = $this->getAllowedDistrictIdsForCurrentUser();

        // Грузим активные планы только для точек из разрешённых районов
        $pointPlans = PointPlan::with([
            'subgroupManager:id,first_name,last_name,middle_name',
            'counter:id,first_name,last_name',
            'schedule:id,year',
            'point.district.region:id,name',
            'point.district.groupManager:id,first_name,last_name,middle_name',
        ])
            ->where('is_active', true)
            ->whereHas('point', function ($q) use ($allowedDistrictIds) {
                $q->whereIn('district_id', $allowedDistrictIds);
            })
            ->get();

        return response()->json([
            'point_plans' => PointPlanResource::collection($pointPlans),
        ]);
    }

    public function getPointPlanInfo($id): JsonResponse
    {
        $point_plan = PointPlan::with([
            'subgroupManager:id,first_name,middle_name,last_name',
            'counter:id,first_name,last_name',
            'point.district.region',
        ])->findOrFail($id);

        return response()->json(['point_plan' => $point_plan]);
    }

    public function updatePointPlan(Request $request, int $id): JsonResponse
    {
        $authUser = Auth::user();

        $validated = $request->validate([
            'day' => ['required', 'date'],
            'timeStart' => ['required', 'date_format:H:i'],
            'timeEnd' => ['required', 'date_format:H:i'],
            'comment' => ['nullable', 'string', 'max:255'],
            'subgroup_manager_id' => ['nullable', 'exists:users,id'],
            'counter_id' => ['nullable', 'exists:counters,id'],
        ]);

        $pointPlan = PointPlan::findOrFail($id);

        // Разрешаем региональному менеджеру вносить только комментарии, даже если уже подписано
        $isSigned = $this->isRequestMonthSigned(
            $pointPlan->request_id,
            $validated['day']
        );
        if ($isSigned && !($authUser->hasRole('Региональный менеджер') || $authUser->hasRole('Администратор') || $authUser->hasRole('Разработчик'))) {
            return response()->json([
                'error' => 'План по этой заявке и месяцу уже подписан. Редактирование запрещено.',
            ], 403);
        }

        // Проверяем конфликт назначения
        if ($request->has('counter_id')
            && $validated['counter_id'] !== null
            && $validated['counter_id'] !== $pointPlan->counter_id
        ) {
            $conflictCounter = PointPlan::where('counter_id', $validated['counter_id'])
                ->where('day', $validated['day'])
                ->where('timeStart', $validated['timeStart'])
                ->where('id', '!=', $id)
                ->where('is_active', true)
                ->exists();

            if ($conflictCounter) {
                return response()->json([
                    'message' => 'Этот учётчик уже назначен на другую точку в это же время.',
                ], 409);
            }
        }

        // Обновляем план
        $updateData = [
            'day' => $validated['day'],
            'timeStart' => $validated['timeStart'],
            'timeEnd' => $validated['timeEnd'],
        ];
        if (array_key_exists('comment', $validated)
            && trim($validated['comment']) !== '')
        {
            // отправляем уведомление о замечаниях
            $user = User::find($pointPlan->subgroup_manager_id);

            if ($user) {
                $user->userNotifications()->create([
                    'title'   => "Замечания в плане работы",
                    'content' => "Поступили замечания в плане работы на точку "
                        . $pointPlan->point->name . ".",
                ]);
            } else {
                // Если менеджера подгруппы нет — уведомим руководителя района
                $districtManagerId = $pointPlan->point->district->manager_id;
                if ($districtManager = User::find($districtManagerId)) {
                    $districtManager->userNotifications()->create([
                        'title'   => "Замечания в плане работы",
                        'content' => "Для плана точки {$pointPlan->point->name} "
                            ."поступили замечания, но Менеджер подгруппы не назначен.",
                    ]);
                }
            }

            // К этому моменту в $updateData уже будет записан непустой comment:
            $updateData['comment'] = $validated['comment'];
        }

        if (isset($validated['subgroup_manager_id'])) {
            $updateData['subgroup_manager_id'] = $validated['subgroup_manager_id'];
        }


            $updateData['counter_id'] = $validated['counter_id'];



        $pointPlan->update($updateData);

        return response()->json([
            'message' => 'План работ успешно обновлен.',
        ]);
    }

    public
    function delPointPlan($id): JsonResponse
    {
        $pointPlan = PointPlan::find($id);

        $request_id = $pointPlan->point->requests()->first()?->id;

        if ($request_id && $this->isRequestMonthSigned($request_id, $pointPlan->day)) {
            return response()->json([
                'error' => 'План по этой заявке и месяцу уже подписан. Удаление запрещено.',
            ], 403);
        }

        $pointPlan->update([
            'is_active' => false,
        ]);
        return response()->json([
            'message' => 'График точки удален.',
        ]);
    }


    public
    function editProposeOperatorToPointPlan(Request $request): JsonResponse
    {
        $authUser = Auth::user();
        $validated = $request->validate([
            'point_plan_id' => ['required', 'exists:point_plans,id'],
            'subgroup_manager_id' => ['required', 'exists:users,id'],
        ]);
        $user = User::findOrFail($validated['subgroup_manager_id']);

        $plan = PointPlan::findOrFail($validated['point_plan_id']);
        $subgroup_manager_id = $validated['subgroup_manager_id'];

        $count = PointPlan::where('subgroup_manager_id', $subgroup_manager_id)
            ->whereDate('day', $plan->day)
            ->count();
        if ($count >= 2) {
            return response()->json([
                'error' => 'Учетчик уже назначен на 2 точки в этот день',
            ], 400);
        }
        // Назначаем оператора
        $plan->update(['subgroup_manager_id' => $validated['subgroup_manager_id']]);
        $user->userNotifications()->create([
            'title' => "Назначение Менеджера подгруппы на точку на точку",
            'content' => 'Вы назначены на проведение работ ' . $plan->id . ' по точке ' . $plan->point_id . '.',
        ]);

        Log::create([
            'model_id' => $plan->id,
            'model_type' => PointPlan::class,
            'change' => 'Менеджер подгруппы',
            'action' => 'на план работ ' . $plan->id . ' по точке ' . $plan->point_id . ' назначен менеджером подгруппы',
            'old_value' => '',
            'new_value' => $user->fullName(),
            'created_by' => $authUser->id,
        ]);
        return response()->json([
            'message' => 'Менеджер подгруппы успешно назначен на точку',
            'plan_id' => $plan->id,
            'subgroup_manager_id' => $subgroup_manager_id,
        ]);
    }

    public function signRequestPlan(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'request_id' => 'required|exists:requests,id',
            'month' => 'required|integer|min:1|max:12',
            'year' => 'required|integer|min:2020',
            'signature' => 'required|string',
            'public_key' => 'required|string',
        ]);

        $record = RequestPlanSignature::updateOrCreate(
            [
                'request_id' => $validated['request_id'],
                'month' => $validated['month'],
                'year' => $validated['year'],
            ],
            [
                'signature' => $validated['signature'],
                'signature_public_key' => $validated['public_key'],
                'is_signed' => true,
            ]
        );

        return response()->json(['status' => 'signed', 'data' => $record]);
    }

    public function getFilteredPoints(Request $request, $id)
    {
        $requestId = $request->query('request_id');
        $month = $request->query('month'); // integer (1-12)
        $districtId = $request->query('district_id');

        $pointsQuery = Point::with(['plans' => function ($q) use ($id, $month) {
            $q->where('schedule_id', $id)
                ->whereMonth('day', $month);
        }, 'plans.subgroupManager:id,name', 'plans.counter:id,name']);

        if ($requestId) {
            $pointsQuery->whereHas('requests', fn($q) => $q->where('request_id', $requestId));
        }

        if ($districtId) {
            $pointsQuery->where('district_id', $districtId);
        }

        $points = $pointsQuery->get();

        return SchedulePointResource::collection($points);
    }

    public function getCalendarMeta($id)
    {
        $plan = SchedulePlan::with(['requests:id,name', 'signedRequests'])
            ->select('id', 'year')
            ->findOrFail($id);

        $calendar = \App\Services\CalendarService::build($plan->year);

        return response()->json([
            'year' => $plan->year,
            'calendar' => $calendar,
            'requests' => $plan->requests,
            'signed_requests' => $plan->signedRequests,
        ]);
    }

    public function calendarView(Request $request, $scheduleId)
    {
        $allowed = $this->getAllowedDistrictIdsForCurrentUser();

        $plan = SchedulePlan::findOrFail($scheduleId);
        $year = $plan->year;

        $calendar = CalendarService::build(
            SchedulePlan::findOrFail($scheduleId)->year
        );

        $points = Point::with([
            'district.region',
            // подгружаем сами планы
            'plans' => fn($q) => $q
                ->where('schedule_id', $scheduleId)
                ->where('is_active', true)
                ->when($request->filled('request_id'), fn($q) => $q->where('request_id', $request->request_id)),
            // **И обязательно подгружаем связанных subgroupManager'ов**
            'plans.subgroupManager',
            'requests',
        ])
            ->whereIn('district_id', $allowed)
            ->when($request->filled('request_id'), function($q) use($request) {
                $q->whereHas('requests', fn($q2) => $q2->where('requests.id', $request->request_id));
            })
            ->get();

        $grouped = $points
            ->groupBy(fn($p) => $p->district->region->name)
            ->map(fn($regionPoints) => [
                'districts' => $regionPoints
                    ->groupBy('district.name')
                    ->map(fn($districtPoints) => [
                        'name' => $districtPoints->first()->district->name,
                        'points' => $districtPoints->map(fn($point) => [
                            'id' => $point->id,
                            'name' => $point->name,
                            'latitude' => $point->latitude,
                            'longitude' => $point->longitude,
                            'record_number' => $point->record_number,
                            'monitoring_freq' => $point->monitoring_freq,
                            'accounting_flag' => $point->accounting_flag,
                            'request_label' => $point->request_label,
                            'subgroup_manager_id'   => $point->district->subgroup_manager_id,
                            'subgroup_manager_name' => optional($point->district->subgroupManager)->fullName(),
                            'plans' => $point->plans->map(fn($pp) => [
                                'day' => $pp->day,
                                'timeStart' => $pp->timeStart->format('H:i'),
                                'timeEnd' => $pp->timeEnd->format('H:i'),
                                'request_id'  => $pp->request_id,
                                'subgroup_manager_id'   => $pp->subgroup_manager_id,
                                'subgroup_manager_name' => $pp->subgroupManager?->fullName(),
                            ])->values(),
                            'requests' => $point->requests->map(fn($r) => [
                                'id' => $r->id,
                                'name' => $r->name,
                            ])->values(),
                        ])->values(),
                    ])->values(),
            ])->values();

        $signedRequests = RequestPlanSignature::query()
            ->where('year', $year)
            // если фронт отфильтровал по конкретной заявке — сузим выборку
            ->when($request->filled('request_id'), fn($q) => $q->where('request_id', $request->request_id))
            ->get(['request_id', 'month', 'year'])
            ->map(fn($sig) => [
                'request_id' => $sig->request_id,
                'month'      => $sig->month,
                'year'       => $sig->year,
            ])
            ->values();

        return response()->json([
            'year' => SchedulePlan::findOrFail($scheduleId)->year,
            'calendar' => $calendar,
            'points' => $grouped,
            'signed_requests' => $signedRequests,  // как у вас было
        ]);
    }


    /**
     * Возвращает подписанные месяцы по конкретной заявке
     */
    public function calendarViewByRequest($requestId)
    {
        $signed = RequestPlanSignature::where('request_id', $requestId)
            ->select(['year', 'month'])
            ->distinct() // сразу убираем дубли
            ->get();

        return response()->json([
            'signed_periods' => $signed,
        ]);
    }


}
