<?php

namespace App\Http\Controllers;

use App\Exceptions\DuplicateCcliSongException;
use App\Models\ServiceSong;
use App\Models\Song;
use App\Services\CcliImportService;
use App\Services\CcliPasteParser;
use App\Services\CcliTranslationPairingService;
use App\Services\SongMatchingService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use Inertia\Inertia;
use Inertia\Response as InertiaResponse;
use InvalidArgumentException;
use RuntimeException;
use Throwable;

final class CcliPasteController extends Controller
{
    public function __construct(
        private readonly CcliPasteParser $parser,
        private readonly CcliImportService $importService,
        private readonly CcliTranslationPairingService $pairingService,
        private readonly SongMatchingService $matchingService,
    ) {}

    /**
     * POST /api/ccli/preview
     * Parse raw text and return DTO as JSON. No DB writes.
     */
    public function preview(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'raw_text' => ['required', 'string', 'max:200000'],
        ]);

        try {
            $parsed = $this->parser->parse($validated['raw_text']);
        } catch (InvalidArgumentException $e) {
            return response()->json([
                'message' => $e->getMessage(),
            ], 422);
        }

        return response()->json([
            'title' => $parsed->title,
            'author' => $parsed->author,
            'ccliId' => $parsed->ccliId,
            'year' => $parsed->year,
            'copyrightText' => $parsed->copyrightText,
            'sections' => array_map(fn ($s) => [
                'label' => $s->label,
                'kind' => $s->kind,
                'number' => $s->number,
                'modifier' => $s->modifier,
                'lines' => $s->lines,
                'hasTranslation' => $s->linesTranslated !== null,
            ], $parsed->sections),
        ]);
    }

    /**
     * POST /api/songs/import-from-ccli-paste
     * Import a CCLI paste in one of 3 modes.
     */
    public function importPaste(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'raw_text' => ['required', 'string', 'max:200000'],
            'mode' => ['required', Rule::in(['create', 'pair-with-song', 'assign-to-service-song'])],
            'target_id' => ['required_unless:mode,create', 'nullable', 'integer'],
            'source_url' => ['nullable', 'string', 'max:500'],
        ]);

        $rawText = $validated['raw_text'];
        $mode = $validated['mode'];
        $targetId = $validated['target_id'] ?? null;
        $sourceUrl = $validated['source_url'] ?? null;

        try {
            if ($mode === 'create') {
                $result = $this->importService->import($rawText, $sourceUrl);

                return response()->json([
                    'song_id' => $result['song']->id,
                    'status' => $result['status'],
                    'warnings' => $result['warnings'],
                ], 201);
            }

            if ($mode === 'pair-with-song') {
                $localSong = Song::findOrFail($targetId);
                $result = $this->pairingService->pair($localSong, $rawText);

                session()->flash('ccli_prefilled', $result['distributed_text']);

                return response()->json([
                    'song_id' => $localSong->id,
                    'mapping' => $result['mapping'],
                    'unmatched_labels' => $result['unmatched_labels'],
                    'redirect_to' => route('songs.translate', $localSong->id).'?prefilled=true',
                ]);
            }

            if ($mode === 'assign-to-service-song') {
                $result = $this->importService->import($rawText, $sourceUrl);
                $song = $result['song'];

                $serviceSong = ServiceSong::findOrFail($targetId);
                $this->matchingService->manualAssign($serviceSong, $song);

                return response()->json([
                    'song_id' => $song->id,
                    'service_song_id' => $serviceSong->id,
                    'status' => $result['status'],
                ], 201);
            }
        } catch (DuplicateCcliSongException $e) {
            return response()->json([
                'message' => $e->getMessage(),
                'existing_song_id' => $e->existingSongId,
                'edit_url' => route('songs.index').'#song-'.$e->existingSongId,
            ], 409);
        } catch (InvalidArgumentException $e) {
            return response()->json(['message' => $e->getMessage()], 422);
        } catch (RuntimeException $e) {
            return response()->json(['message' => $e->getMessage()], 422);
        }

        return response()->json(['message' => 'Unbekannter Modus'], 422);
    }

    /**
     * GET /songs/import-from-ccli-paste
     * Render the Inertia page for bookmarklet redirect.
     */
    public function showImportPage(Request $request): InertiaResponse
    {
        $prefill = $request->query('prefill');
        $prefilledText = null;
        $prefilledMetadata = null;
        $prefillError = null;

        if ($prefill !== null && is_string($prefill)) {
            try {
                $decoded = base64_decode($prefill, strict: true);
                if ($decoded === false) {
                    throw new InvalidArgumentException('Ungültige Kodierung');
                }
                $payload = json_decode($decoded, associative: true, flags: JSON_THROW_ON_ERROR);

                if (! is_array($payload)) {
                    throw new InvalidArgumentException('Ungültiges Payload-Format');
                }

                $prefilledText = $payload['rawText'] ?? null;
                $prefilledMetadata = [
                    'title' => $payload['title'] ?? null,
                    'author' => $payload['author'] ?? null,
                    'ccliId' => $payload['ccliId'] ?? null,
                    'sourceUrl' => $payload['sourceUrl'] ?? null,
                ];
            } catch (Throwable) {
                $prefillError = 'Lesezeichen-Daten konnten nicht gelesen werden. Bitte den Liedtext manuell einfügen.';
            }
        }

        return Inertia::render('Songs/ImportFromCcliPaste', [
            'prefilledText' => $prefilledText,
            'prefilledMetadata' => $prefilledMetadata,
            'prefillError' => $prefillError,
        ]);
    }
}
