<?php

namespace App\Http\Controllers;

use App\Models\SportsMatch;
use App\Services\NasSyncService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\Rule;

class SportsMatchController extends Controller
{
    /** Single-image fields stored under the `media` JSON group. */
    private const IMAGE_FIELDS = [
        'media_participant1_photo' => 'participant1_photo',
        'media_participant2_photo' => 'participant2_photo',
        'media_referee_photo'      => 'referee_photo',
        'media_club1_logo'         => 'club1_logo',
        'media_club2_logo'         => 'club2_logo',
        'media_event_poster'       => 'event_poster',
    ];

    public function store(Request $request, NasSyncService $nas): JsonResponse
    {
        $data = $request->validate($this->rules());

        $match = new SportsMatch();
        $match->user_id = Auth::id();
        $this->fillFromRequest($match, $request, $data);
        $match->save();

        $this->handleImages($match, $request, $nas);
        $match->save();

        return response()->json([
            'ok'      => true,
            'message' => 'Match saved as draft.',
            'match'   => $this->toEditPayload($match),
        ]);
    }

    public function update(Request $request, SportsMatch $sportsMatch, NasSyncService $nas): JsonResponse
    {
        abort_unless($sportsMatch->user_id === Auth::id(), 403);

        $data = $request->validate($this->rules($sportsMatch));

        $this->fillFromRequest($sportsMatch, $request, $data);
        $this->handleImages($sportsMatch, $request, $nas);
        $sportsMatch->save();

        return response()->json([
            'ok'      => true,
            'message' => 'Match updated.',
            'match'   => $this->toEditPayload($sportsMatch),
        ]);
    }

    /** Return the record as JSON so the modal can be re-opened for later editing. */
    public function edit(SportsMatch $sportsMatch): JsonResponse
    {
        abort_unless($sportsMatch->user_id === Auth::id(), 403);

        return response()->json(['match' => $this->toEditPayload($sportsMatch)]);
    }

    // ── Validation ──────────────────────────────────────────────────────────

    private function rules(?SportsMatch $existing = null): array
    {
        $img = ['nullable', 'image', 'mimes:jpg,jpeg,png,webp', 'max:5120'];

        return [
            // Basic — only these are required for a first (draft) save
            'video_id'          => ['required', 'integer', Rule::exists('videos', 'id')->where('user_id', Auth::id())],
            'status'            => ['nullable', Rule::in(['draft', 'published'])],
            'title'             => ['required', 'string', 'max:255'],
            'event_name'        => ['nullable', 'string', 'max:255'],
            'match_date'        => ['nullable', 'date'],
            'match_time'        => ['nullable', 'date_format:H:i'],
            'participant1_name' => ['nullable', 'string', 'max:255'],
            'participant2_name' => ['nullable', 'string', 'max:255'],
            'referee_name'      => ['nullable', 'string', 'max:255'],
            // revealed later in edit
            'sport'             => ['nullable', 'string', 'max:80'],
            'match_type'        => ['nullable', 'string', 'max:80'],
            'venue_name'        => ['nullable', 'string', 'max:255'],

            // Optional grouped scalars (free-form, kept generic)
            'competition'       => ['nullable', 'array'],
            'participants'      => ['nullable', 'array'],
            'extra_participants'=> ['nullable', 'array'],
            'venue'             => ['nullable', 'array'],
            'result'            => ['nullable', 'array'],
            'reviews'           => ['nullable', 'array'],
            'media'             => ['nullable', 'array'],

            // Repeatable groups
            'officials'           => ['nullable', 'array'],
            'officials.*.role'    => ['nullable', 'string', 'max:80'],
            'officials.*.name'    => ['nullable', 'string', 'max:255'],
            'officials.*.photo'   => $img,

            'segments'            => ['nullable', 'array'],
            'segments.*.type'     => ['nullable', 'string', 'max:80'],
            'segments.*.number'   => ['nullable', 'string', 'max:50'],
            'segments.*.score'    => ['nullable', 'string', 'max:255'],
            'segments.*.winner'   => ['nullable', 'string', 'max:255'],
            'segments.*.notes'    => ['nullable', 'string', 'max:2000'],

            'statistics'          => ['nullable', 'array'],
            'statistics.*.name'   => ['nullable', 'string', 'max:120'],
            'statistics.*.value'  => ['nullable', 'string', 'max:120'],
            'statistics.*.owner'  => ['nullable', 'string', 'max:255'],
            'statistics.*.notes'  => ['nullable', 'string', 'max:2000'],

            // Single image fields
            'media_participant1_photo' => $img,
            'media_participant2_photo' => $img,
            'media_referee_photo'      => $img,
            'media_club1_logo'         => $img,
            'media_club2_logo'         => $img,
            'media_event_poster'       => $img,
        ];
    }

    // ── Mapping helpers ─────────────────────────────────────────────────────

    private function fillFromRequest(SportsMatch $match, Request $request, array $data): void
    {
        $match->video_id          = $data['video_id'];
        $match->status            = $data['status'] ?? 'draft';
        $match->title             = $data['title'];
        $match->event_name        = $data['event_name'] ?? null;
        $match->match_date        = $data['match_date'] ?? null;
        $match->match_time        = $data['match_time'] ?? null;
        $match->participant1_name = $data['participant1_name'] ?? null;
        $match->participant2_name = $data['participant2_name'] ?? null;
        $match->referee_name      = $data['referee_name'] ?? null;
        $match->sport             = $data['sport'] ?? null;
        $match->match_type        = $data['match_type'] ?? null;
        $match->venue_name        = $data['venue_name'] ?? null;

        // Optional scalar groups — keep only non-empty values, drop the JSON if empty.
        $match->competition = $this->clean($request->input('competition', []));
        $match->venue       = $this->clean($request->input('venue', []));
        $match->result      = $this->clean($request->input('result', []));
        $match->reviews     = $this->clean($request->input('reviews', []));

        // Participants details + any extra participants in one generic structure.
        $participants = $this->clean($request->input('participants', []));
        $extra = collect($request->input('extra_participants', []))
            ->map(fn ($p) => $this->clean($p))
            ->filter()
            ->values()
            ->all();
        if (! empty($extra)) $participants['extra'] = $extra;
        $match->participants = empty($participants) ? null : $participants;

        // Repeatable text groups (officials are built in handleImages() since they carry photos).
        $match->segments   = $this->cleanRows($request->input('segments', []));
        $match->statistics = $this->cleanRows($request->input('statistics', []));

        // Media text fields (caption/alt/credit/public). Preserve existing image
        // paths already on the record; handleImages() overwrites any replaced ones.
        $existingMedia = $match->media ?? [];
        $mediaText = $this->clean($request->input('media', []));
        if (isset($mediaText['public'])) {
            $mediaText['public'] = filter_var($mediaText['public'], FILTER_VALIDATE_BOOLEAN);
        }
        $imagePaths = array_intersect_key($existingMedia, array_flip(self::IMAGE_FIELDS));
        $merged = array_merge($imagePaths, $mediaText);
        $match->media = empty($merged) ? null : $merged;
    }

    /** Strip empty values from a flat associative array; return null if nothing left. */
    private function clean(?array $arr): ?array
    {
        if (! is_array($arr)) return null;
        $out = array_filter($arr, fn ($v) => $v !== null && $v !== '' && $v !== []);
        return empty($out) ? null : $out;
    }

    /** Clean a list of repeatable rows, dropping rows that are entirely empty. */
    private function cleanRows(?array $rows): ?array
    {
        if (! is_array($rows)) return null;
        $out = [];
        foreach ($rows as $row) {
            if (! is_array($row)) continue;
            // photo (file) is handled separately; drop transient hidden keys here
            unset($row['photo']);
            $clean = $this->clean($row);
            if ($clean) $out[] = $clean;
        }
        return empty($out) ? null : $out;
    }

    // ── Image handling ──────────────────────────────────────────────────────

    private function handleImages(SportsMatch $match, Request $request, NasSyncService $nas): void
    {
        $slug  = $nas->userSlug($match->user ?: Auth::user());
        $media = $match->media ?? [];

        // Named single images
        foreach (self::IMAGE_FIELDS as $input => $key) {
            if ($request->hasFile($input)) {
                $media[$key] = $this->storeImage($request->file($input), $slug, $match->id, $key, $nas);
            }
        }
        $match->media = empty($media) ? null : $media;

        // Officials — built from raw input so file inputs align by index. The
        // modal renumbers rows to contiguous indices before submit. A new photo
        // file replaces the existing one; otherwise the existing path is kept.
        $officials = [];
        foreach (array_values($request->input('officials', [])) as $i => $row) {
            if (! is_array($row)) continue;
            $entry = [];
            if (! empty($row['role'])) $entry['role'] = $row['role'];
            if (! empty($row['name'])) $entry['name'] = $row['name'];
            if ($request->hasFile("officials.$i.photo")) {
                $entry['photo'] = $this->storeImage(
                    $request->file("officials.$i.photo"), $slug, $match->id, "official-$i", $nas
                );
            } elseif (! empty($row['photo_existing'])) {
                $entry['photo'] = $row['photo_existing'];
            }
            if (! empty($entry)) $officials[] = $entry;
        }
        $match->officials = empty($officials) ? null : $officials;
    }

    /**
     * Write one uploaded image to the canonical NAS path
     * (users/{slug}/sports/{matchId}/{key}.{ext}) and return that relative path.
     */
    private function storeImage(UploadedFile $file, string $slug, int $matchId, string $key, NasSyncService $nas): string
    {
        $ext = strtolower($file->getClientOriginalExtension() ?: 'jpg');
        $rel = "users/{$slug}/sports/{$matchId}/{$key}.{$ext}";
        $localAbs = storage_path('app/' . $rel);

        @mkdir(dirname($localAbs), 0755, true);
        $file->move(dirname($localAbs), basename($localAbs));

        // Push to NAS and drop the local copy when the NAS is reachable.
        if ($nas->isEnabled()) {
            $nas->mkdirp(dirname($rel));
            if ($nas->putFile($localAbs, $rel)) {
                @unlink($localAbs);
            }
        }

        return $rel;
    }

    /** Shape the record for the edit modal (resolves image paths to URLs). */
    private function toEditPayload(SportsMatch $match): array
    {
        $media = $match->media ?? [];
        $mediaUrls = [];
        // Key the URLs by the form input name (e.g. media_participant1_photo) so the
        // modal can match each preview to its field via [data-img].
        foreach (self::IMAGE_FIELDS as $input => $key) {
            if (! empty($media[$key])) {
                $mediaUrls[$input] = route('media.sports-image', $media[$key]);
            }
        }

        $officials = $match->officials ?? [];
        foreach ($officials as &$o) {
            if (! empty($o['photo'])) $o['photo_url'] = route('media.sports-image', $o['photo']);
        }
        unset($o);

        return [
            'id'                => $match->id,
            'video_id'          => $match->video_id,
            'video_title'       => optional($match->video)->title,
            'status'            => $match->status,
            'sport'             => $match->sport,
            'title'             => $match->title,
            'event_name'        => $match->event_name,
            'match_type'        => $match->match_type,
            'match_date'        => optional($match->match_date)->format('Y-m-d'),
            'match_time'        => $match->match_time ? substr($match->match_time, 0, 5) : null,
            'participant1_name' => $match->participant1_name,
            'participant2_name' => $match->participant2_name,
            'referee_name'      => $match->referee_name,
            'venue_name'        => $match->venue_name,
            'competition'       => $match->competition,
            'participants'      => $match->participants,
            'venue'             => $match->venue,
            'result'            => $match->result,
            'reviews'           => $match->reviews,
            'media'             => $media,
            'media_urls'        => $mediaUrls,
            'officials'         => $officials,
            'segments'          => $match->segments,
            'statistics'        => $match->statistics,
        ];
    }
}
