<?php

namespace App\Http\Controllers;

use App\Events\DocumentGenerated;
use App\Models\Activity;
use App\Models\Contract;
use App\Models\Document;
use App\Models\DocumentTemplate;
use App\Services\Documents\TokenValueResolver;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Str;
use Symfony\Component\HttpFoundation\Response;

class ContractDocumentGenerationController extends Controller
{
    public function __invoke(Request $request, Contract $contract): Response|RedirectResponse
    {
        // Inertia requests include the X-Inertia header and should receive redirects or Inertia responses, not JSON
        $isInertia = (bool) $request->header('X-Inertia');
        // For non-Inertia POSTs, prefer JSON responses by default (including tests)
        $wantsJson = ! $isInertia;
        if (Gate::denies('read')) { // baseline read permission required to generate
            abort(403);
        }
        $request->validate([
            'template_slug' => ['required', 'string', 'exists:document_templates,slug'],
            'template_version' => ['nullable', 'integer'],
            'custom' => ['nullable', 'array'],
            'custom.*' => ['nullable'],
        ]);

        // Prefer explicitly requested version if provided and active; otherwise use latest active
        $baseQuery = DocumentTemplate::query()
            ->where('slug', $request->template_slug)
            ->where('core_entity', 'contract')
            ->where('active', true);
        if ($request->filled('template_version')) {
            $template = (clone $baseQuery)->where('version', (int) $request->integer('template_version'))->first();
            if (! $template) {
                $template = (clone $baseQuery)->orderByDesc('version')->firstOrFail();
            }
        } else {
            $template = $baseQuery->orderByDesc('version')->firstOrFail();
        }

        // Load related data minimally
        $contract->load(['clientCase.client.person', 'clientCase.person', 'clientCase.client']);

        $renderer = app(\App\Services\Documents\DocxTemplateRenderer::class);
        try {
            // For custom tokens: pass overrides via request bag; service already reads request()->input('custom') if present.
            $result = $renderer->render($template, $contract, Auth::user());
        } catch (\App\Services\Documents\Exceptions\UnresolvedTokensException $e) {
            if ($wantsJson) {
                return response()->json([
                    'status' => 'error',
                    'message' => 'Unresolved tokens detected.',
                    'tokens' => $e->unresolved ?? [],
                ], 500);
            }

            // Return back with validation-like errors so Inertia can surface them via onError
            return back()->withErrors([
                'document' => 'Unresolved tokens detected.',
            ])->with('unresolved_tokens', $e->unresolved ?? []);
        } catch (\Throwable $e) {
            try {
                logger()->error('ContractDocumentGenerationController generation failed', [
                    'template_id' => $template->id ?? null,
                    'template_slug' => $template->slug ?? null,
                    'template_version' => $template->version ?? null,
                    'error' => $e->getMessage(),
                ]);
            } catch (\Throwable $logEx) {
            }

            if ($wantsJson) {
                return response()->json([
                    'status' => 'error',
                    'message' => 'Generation failed.',
                ], 500);
            }

            return back()->withErrors([
                'document' => 'Generation failed.',
            ]);
        }

        $doc = new Document;
        $doc->fill([
            'uuid' => (string) Str::uuid(),
            'name' => $result['fileName'],
            'description' => 'Generated from template '.$template->slug.' v'.$template->version,
            'user_id' => Auth::id(),
            'disk' => 'public',
            'path' => $result['relativePath'],
            'file_name' => $result['fileName'],
            'original_name' => $result['fileName'],
            'extension' => 'docx',
            'mime_type' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
            'size' => $result['size'],
            'checksum' => $result['checksum'],
            'is_public' => true,
            'template_id' => $template->id,
            'template_version' => $template->version,
        ]);
        $contract->documents()->save($doc);

        // Dispatch domain event
        event(new DocumentGenerated($doc));

        // Optional: create an activity if template links to action/decision
        if (($template->action_id || $template->decision_id || $template->activity_note_template) && $contract->client_case_id) {
            try {
                $note = null;
                if ($template->activity_note_template) {
                    // Interpolate tokens in note using existing resolver logic (non-failing policy: keep)
                    /** @var TokenValueResolver $resolver */
                    $resolver = app(TokenValueResolver::class);
                    $rawNote = $template->activity_note_template;
                    $tokens = [];
                    if (preg_match_all('/\{([a-zA-Z0-9_\.]+)\}/', $rawNote, $m)) {
                        $tokens = array_unique($m[1]);
                    }
                    $values = [];
                    if ($tokens) {
                        $resolved = $resolver->resolve($tokens, $template, $contract, Auth::user(), 'keep');
                        foreach ($resolved['values'] as $k => $v) {
                            $values['{'.$k.'}'] = $v;
                        }
                    }
                    $note = strtr($rawNote, $values);
                }

                Activity::create(array_filter([
                    'note' => $note,
                    'action_id' => $template->action_id,
                    'decision_id' => $template->decision_id,
                    'contract_id' => $contract->id,
                    'client_case_id' => $contract->client_case_id,
                ], fn ($v) => ! is_null($v) && $v !== ''));
            } catch (\Throwable $e) {
                // swallow activity creation errors to not block document generation
            }
        }

        if ($wantsJson) {
            return response()->json([
                'status' => 'ok',
                'document_uuid' => $doc->uuid,
                'path' => $doc->path,
                'stats' => $result['stats'] ?? null,
                'template' => [
                    'id' => $template->id,
                    'slug' => $template->slug,
                    'version' => $template->version,
                    'file_path' => $template->file_path,
                ],
            ]);
        }

        // Flash some lightweight info if needed by the UI; Inertia will GET the page after redirect
        return back()->with([
            'doc_generated' => [
                'uuid' => $doc->uuid,
                'path' => $doc->path,
                'template' => [
                    'slug' => $template->slug,
                    'version' => $template->version,
                ],
                'stats' => $result['stats'] ?? null,
            ],
        ]);
    }
}
