<?php

namespace App\Http\Controllers;

use App\Models\RosterResultUpload;
use App\Services\ApiResponseCache;
use App\Services\CsvRosterResultImporter;
use App\Services\RosterResultMatcher;
use App\Support\RosterData;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;

class RosterResultController extends Controller
{
    public function __construct(
        private readonly CsvRosterResultImporter $importer,
        private readonly RosterResultMatcher $matcher,
    ) {
    }

    public function index(Request $request): JsonResponse
    {
        $team = RosterData::normalizeTeam($request->string('team', 'designers')->toString());
        $rosterDate = RosterData::normalizeDate($request->string('roster_date', now()->toDateString())->toString(), now()->toDateString());
        $userFilter = trim($request->string('user', '')->toString());
        $perPage = min(max((int) $request->integer('per_page', 25), 1), 100);
        $page = max((int) $request->integer('page', 1), 1);

        $upload = $this->resolveUpload($request, $team, $rosterDate);
        $rows = $this->matcher->buildRows($team, $rosterDate, $upload);

        if ($userFilter !== '' && $userFilter !== 'All Users') {
            $rows = $rows->where('user', $userFilter)->values();
        }

        $paginator = new LengthAwarePaginator(
            $rows->forPage($page, $perPage)->values(),
            $rows->count(),
            $perPage,
            $page,
            [
                'path' => $request->url(),
                'query' => $request->query(),
            ]
        );

        return response()->json(array_merge($paginator->toArray(), [
            'summary' => $this->matcher->summarize($rows),
            'upload' => $this->uploadPayload($upload),
        ]));
    }

    public function uploads(Request $request): JsonResponse
    {
        $team = RosterData::normalizeTeam($request->string('team', 'designers')->toString());
        $rosterDate = RosterData::normalizeDate($request->string('roster_date', now()->toDateString())->toString(), now()->toDateString());

        $uploads = RosterResultUpload::query()
            ->where('team', $team)
            ->whereDate('roster_date', $rosterDate)
            ->latest()
            ->get()
            ->map(fn (RosterResultUpload $upload) => $this->uploadPayload($upload))
            ->values();

        return response()->json([
            'data' => $uploads,
            'latest' => $uploads->first(),
        ]);
    }

    public function upload(Request $request, ApiResponseCache $apiResponseCache): JsonResponse
    {
        $payload = $request->validate([
            'team' => ['required', 'string', 'in:designers,qa'],
            'roster_date' => ['required', 'date'],
            'file' => ['required', 'file', 'mimes:csv,txt', 'max:5120'],
        ]);

        $team = RosterData::normalizeTeam($payload['team']);
        $rosterDate = RosterData::normalizeDate($payload['roster_date'], now()->toDateString());
        $upload = $this->importer->import($request->file('file'), $team, $rosterDate, $request->user()?->id);
        $apiResponseCache->invalidateGroups(['roster_results']);

        return response()->json([
            'message' => "Imported {$upload->imported_rows} CSV rows.",
            'upload' => $this->uploadPayload($upload),
        ], 201);
    }

    public function match(Request $request, ApiResponseCache $apiResponseCache): JsonResponse
    {
        $payload = $request->validate([
            'team' => ['required', 'string', 'in:designers,qa'],
            'roster_date' => ['required', 'date'],
            'upload_id' => ['nullable', 'integer'],
        ]);

        $team = RosterData::normalizeTeam($payload['team']);
        $rosterDate = RosterData::normalizeDate($payload['roster_date'], now()->toDateString());
        $upload = $this->resolveUpload($request, $team, $rosterDate);

        if (! $upload) {
            return response()->json([
                'message' => 'No CSV upload is available for the selected team and date.',
                'summary' => $this->matcher->summarize(collect()),
                'upload' => null,
            ]);
        }

        $rows = $this->matcher->buildRows($team, $rosterDate, $upload);
        $upload->forceFill(['matched_at' => now()])->save();
        $apiResponseCache->invalidateGroups(['roster_results']);

        return response()->json([
            'message' => 'CSV results matched against the saved roster.',
            'summary' => $this->matcher->summarize($rows),
            'upload' => $this->uploadPayload($upload->fresh()),
        ]);
    }

    public function destroy(RosterResultUpload $upload, ApiResponseCache $apiResponseCache): JsonResponse
    {
        $upload->delete();
        $apiResponseCache->invalidateGroups(['roster_results']);

        return response()->json([
            'message' => 'Uploaded CSV removed successfully.',
        ]);
    }

    private function resolveUpload(Request $request, string $team, string $rosterDate): ?RosterResultUpload
    {
        $uploadId = $request->integer('upload_id');

        if ($uploadId) {
            return RosterResultUpload::query()->find($uploadId);
        }

        return $this->matcher->latestUpload($team, $rosterDate);
    }

    private function uploadPayload(?RosterResultUpload $upload): ?array
    {
        if (! $upload) {
            return null;
        }

        return [
            'id' => $upload->id,
            'team' => $upload->team,
            'rosterDate' => $upload->roster_date?->toDateString(),
            'sourceFilename' => $upload->source_filename,
            'importedRows' => $upload->imported_rows,
            'createdAt' => $upload->created_at?->format('Y-m-d h:i A'),
            'matchedAt' => $upload->matched_at?->format('Y-m-d h:i A'),
        ];
    }
}
