<?php

namespace App\Http\Controllers;

use App\Models\Point;
use App\Models\RequestSet;
use App\Models\PointPlan;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
use Maatwebsite\Excel\Facades\Excel;

class RequestController extends Controller
{
    public function index(): JsonResponse
    {
        return response()->json(RequestSet::withCount('points')->get());
    }

    public function store(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'name' => 'required|string',
            'description' => 'nullable|string',
            'is_template' => 'boolean'
        ]);

        $requestSet = RequestSet::create($validated);
        return response()->json(['request' => $requestSet]);
    }

    public function addPointsToRequest(Request $request, $id): JsonResponse
    {
        $validated = $request->validate([
            'point_ids' => 'required|array|min:1',
            'point_ids.*' => 'integer|exists:points,id'
        ]);

        $requestSet = RequestSet::findOrFail($id);
        $requestSet->points()->syncWithoutDetaching($validated['point_ids']);

        return response()->json(['success' => 'Точки добавлены к заявке']);
    }

    public function getPointsByRequest(Request $request, $id): JsonResponse
    {
        $query = RequestSet::findOrFail($id)->points()->with('district.region');

        if ($request->filled('district_id')) {
            $query->where('district_id', $request->district_id);
        }

        if ($request->filled('category')) {
            $query->whereJsonContains('road_category', $request->category);
        }

        if ($request->filled('monitoring_freq')) {
            $query->where('monitoring_freq', $request->monitoring_freq);
        }

        if ($request->filled('month')) {
            $query->whereHas('plans', function ($q) use ($request) {
                $q->whereMonth('day', $request->month);
            });
        }

        return response()->json(['points' => $query->get()]);
    }

    public function update(Request $request, $id): JsonResponse
    {
        $validated = $request->validate([
            'name'        => 'required|string',
            'description' => 'nullable|string',
            'is_template' => 'boolean',
            'point_ids'   => 'sometimes|array|min:0',
            'point_ids.*' => 'integer|exists:points,id',
        ]);

        /** @var RequestSet $requestSet */
        $requestSet = RequestSet::findOrFail($id);

        // 1) Сохраняем старый список точек (до обновления)
        $oldPointIds = $requestSet->points()->pluck('points.id')->toArray();
        // Обновляем поля заявки
        $requestSet->update([
            'name'        => $validated['name'],
            'description' => $validated['description'] ?? $requestSet->description,
            'is_template' => $validated['is_template'] ?? $requestSet->is_template,
        ]);

        // 3) Если пришёл массив point_ids — синхронизуем связи
        if (array_key_exists('point_ids', $validated)) {
            $newPointIds = $validated['point_ids'];

            // 3.1) Найдём те точки, которые были в старом списке, но отсутствуют в новом
            $removedPointIds = array_diff($oldPointIds, $newPointIds);

            // 3.2) Для каждого удалённого point_id деактивируем все соответствующие PointPlan
            if (!empty($removedPointIds)) {
                PointPlan::where('request_id', $id)
                    ->whereIn('point_id', $removedPointIds)
                    ->update(['is_active' => false]);
            }

            // 3.3) Синхронизируем связи «точка ↔ заявка»
            $requestSet->points()->sync($newPointIds);
        }

        return response()->json([
            'request' => $requestSet->fresh()->loadCount('points'),
        ]);
    }

    /**
     * Возвращает JSON-массив объектов (по одной фотографии на точку):
     * [
     *   {
     *     "url": string,
     *     "day": "YYYY-MM-DD",
     *     "timeStart": "HH:MM",
     *     "point": {
     *       "record_number": string,
     *       "name": string,
     *       "latitude": float,
     *       "longitude": float
     *     }
     *   },
     *   …
     * ]
     *
     * @param Request $request
     * @param int     $id         ID заявки
     * @return JsonResponse
     */
    public function photos(Request $request, $id): JsonResponse
    {
        $districtId = $request->query('district_id');

        // Подгружаем все PointPlan по заявке и (опционально) району
        $plans = PointPlan::with([
            'point',
            'files' => fn($q) => $q->whereIn('type', ['before', 'after'])
        ])
            ->where('request_id', $id)
            ->when($districtId, fn($q) => $q->forDistrict((int)$districtId))
            ->orderBy('day')
            ->get();

        $photos = [];

        foreach ($plans as $plan) {
            /** @var PointPlan $plan */
            foreach ($plan->files as $file) {
                // Пропускаем PDF без thumbnail
                $rawPath = $file->thumbnail ?: $file->path;
                if (! $file->thumbnail && Str::endsWith(Str::lower($file->path), '.pdf')) {
                    continue;
                }

                // Ссылка на S3 (или внешний URL, если полный путь)
                $url = Str::startsWith($rawPath, ['http://', 'https://'])
                    ? $rawPath
                    : Storage::disk('s3')->url($rawPath);

                $photos[] = [
                    'url'        => $url,
                    'day'        => $plan->day->toDateString(),
                    'timeStart'  => $plan->timeStart,       // "HH:MM"
                    'point'      => [
                        'record_number' => $plan->point->record_number,
                        'name'          => $plan->point->name,
                        'latitude'      => $plan->point->latitude,
                        'longitude'     => $plan->point->longitude,
                    ],
                ];
            }
        }

        return response()->json($photos);
    }

    /**
     * Импортирует список точек по их названию (столбец `name` в CSV/Excel).
     *
     * В ответ возвращает:
     * - matched_point_ids: [int,…]  – ID точек, найденных в БД по названиям из файла
     * - not_found_names:   [string,…] – названия, которые не удалось найти
     */
    public function importPointsByName(Request $request, $requestId): JsonResponse
    {
        // 1) Проверяем, что файл передан
        if (! $request->hasFile('file')) {
            throw ValidationException::withMessages([
                'file' => ['Необходимо загрузить файл CSV/XLSX.']
            ]);
        }

        $file = $request->file('file');
        $ext = strtolower($file->getClientOriginalExtension());
        if (! in_array($ext, ['csv', 'xlsx', 'xls'])) {
            throw ValidationException::withMessages([
                'file' => ['Неверный формат файла. Доступны CSV, XLSX или XLS.']
            ]);
        }

        /**
         * 2) Читаем первую вкладку целиком в коллекцию.
         * Предполагаем, что в файле есть колонка "name" (или любой другой
         * заголовок с названием точки).
         */
        $rows = Excel::toCollection(null, $file)[0];

        // 2.1) Количество строк в файле (включая, например, строку-заголовок)
        $totalRows = $rows->count();

        // 3) Собираем все значения из колонки "name"
        $uploadedNames = $rows
            ->pluck('0')      // название колонки в файле должно быть точно "name"
            ->filter()           // отброс пустых
            ->map(fn($v) => trim((string)$v))
            ->unique()
            ->toArray();

        if (empty($uploadedNames)) {
            return response()->json([
                'message'          => 'В файле не найдена колонка "0" либо значения пустые.',
                'matched_point_ids'=> [],
                'not_found_names'  => []
            ], 422);
        }

        // 4) Получаем точки из БД, имена которых попадают в этот список
        $points = Point::whereIn('name', $uploadedNames)
            ->get(['id', 'name']);

        // Создаём карту name => id
        $foundMap = $points->pluck('id', 'name')->toArray();
        // Например: [ "Подъезд к с. Романовка" => 42, … ]

        // 5) Вычисляем, какие имена из файла не нашлись в БД
        $notFoundNames = array_diff($uploadedNames, array_keys($foundMap));

        // 6) Собираем ID найденных точек
        $matchedPointIds = array_values($foundMap);

        return response()->json([
            'total_rows'        => $totalRows,
            'matched_point_ids' => $matchedPointIds,
            'not_found_names'   => array_values($notFoundNames),
        ]);
    }

    public function syncPointsAndDeactivatePlans(Request $request, $requestId): JsonResponse
    {
        $validated = $request->validate([
            'point_ids'   => 'required|array|min:0',
            'point_ids.*' => 'integer|exists:points,id',
        ]);

        // 1) Берём запрос
        $requestSet = RequestSet::findOrFail($requestId);

        // 2) Текущий список точек в заявке
        $existingPointIds = $requestSet->points()->pluck('points.id')->toArray();

        // 3) Новый список ID
        $newPointIds = $validated['point_ids'];

        // 4) Вычисляем те, которые нужно удалить (деактивировать)
        $toRemove = array_diff($existingPointIds, $newPointIds);

        // 5) Деактивируем PointPlan для удалённых точек
        if (! empty($toRemove)) {
            PointPlan::where('request_id', $requestId)
                ->whereIn('point_id', $toRemove)
                ->update(['is_active' => false]);
        }

        // 6) Синхронизируем pivot-таблицу point_request
        $requestSet->points()->sync($newPointIds);

        return response()->json([
            'message' => 'Точки синхронизированы. Работы по удалённым точкам деактивированы.',
            'removed_point_ids' => array_values($toRemove),
            'added_point_ids'   => array_values(array_diff($newPointIds, $existingPointIds)),
        ]);
    }

    public function lock(Request $request, $id): JsonResponse
    {
        $user = $request->user();
        // Проверяем, что это региональный менеджер (подставь свой способ проверки)
        if (!$user->hasRole('Региональный менеджер') && !$user->hasRole('Разработчик')) {
            return response()->json(['error' => 'Доступ запрещён'], 403);
        }

        $requestSet = RequestSet::findOrFail($id);
        if ($requestSet->is_locked) {
            return response()->json(['message' => 'Заявка уже подписана'], 400);
        }
        $requestSet->is_locked = true;
        $requestSet->save();

        return response()->json(['message' => 'Заявка успешно подписана', 'request' => $requestSet]);
    }

}
