<?php

namespace App\Components\Template;

use App\Enum\Contact\MessageChannel;
use App\Enum\Contact\TemplateTriggerType;
use App\Models\Claim\Status;
use App\Models\Client\Client;
use App\Models\Contact\ContactCategory;
use App\Models\Contact\ContactTemplate;
use App\Models\Contact\ContactTemplateTrigger;
use App\Models\Contact\Template;
use App\Models\Solicitor\Solicitor;
use App\Models\Solicitor\SolicitorEmailSender;
use App\Models\Solicitor\SolicitorSmsSender;
use App\Services\Communications\Placeholders\PlaceholderRegistry;
use App\Services\Communications\Placeholders\TemplateRenderer;
use App\ValueObjects\Communications\PlaceholderContext;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Livewire\Attributes\Url;
use Livewire\Component;

class Editor extends Component
{
    public ?ContactTemplate $template = null;

    use AuthorizesRequests;

    /* Core fields */
    public ?int $category_id = null;
    public ?string $name = null;
    public ?string $key = null;
    public string $channel = 'email';
    public ?string $subject = null;
    public ?string $body_html_template = null;
    public ?string $body_text_template = null;
    public ?int $default_sender_email_id = null;
    public ?int $default_sms_sender_id = null;
    public ?string $applies_to_type = null;
    public ?string $description = null;
    public bool $is_active = true;
    public bool $allow_manual_send = true;
    public bool $allow_automatic_send = false;
    public bool $include_signature = true;

    /* Preview context */
    #[Url]
    public ?int $previewClientId = null;

    public ?string $previewSubject = null;
    public ?string $previewBodyText = null;
    public ?string $previewBodyHtml = null;
    public array $previewPlaceholdersUsed = [];
    public array $previewUnknown = [];
    public ?int $smsLength = null;
    public ?int $smsSegments = null;
    public ?string $smsEncoding = null;

    /* Trigger editor state */
    public bool $showTriggerForm = false;
    public ?int $editingTriggerId = null;
    public array $triggerForm = [
        'trigger_type' => 'status_changed',
        'model_type' => null,
        'conditions' => '{}',
        'dedupe_window_minutes' => 60,
        'is_active' => true,
    ];

    /** @var array<int, string> */
    public array $unknownAtSave = [];

    protected function rules(): array
    {
        return [
            'name' => 'required|min:2',
            'key' => 'nullable|string|max:255',
            'channel' => 'required|in:email,sms',
            'category_id' => 'nullable|exists:contact_categories,id',
            'subject' => 'nullable|string|max:512',
            'body_text_template' => 'nullable|string',
            'body_html_template' => 'nullable|string',
            'default_sender_email_id' => 'nullable|exists:solicitor_email_senders,id',
            'default_sms_sender_id' => 'nullable|exists:solicitor_sms_senders,id',
            'applies_to_type' => 'nullable|string|max:255',
            'description' => 'nullable|string|max:1000',
        ];
    }

    public function mount(?ContactTemplate $template = null): void
    {
        $this->authorize($template?->exists ? 'templates.edit' : 'templates.create');

        if ($template?->exists) {
            $this->template = $template;
            $this->category_id = $template->category_id;
            $this->name = $template->name;
            $this->key = $template->key;
            $this->channel = $template->channel?->value ?? 'email';
            $this->subject = $template->subject;
            $this->body_html_template = $template->body_html_template;
            $this->body_text_template = $template->body_text_template;
            $this->default_sender_email_id = $template->default_sender_email_id;
            $this->default_sms_sender_id = $template->default_sms_sender_id;
            $this->applies_to_type = $template->applies_to_type;
            $this->description = $template->description;
            $this->is_active = (bool) $template->is_active;
            $this->allow_manual_send = (bool) $template->allow_manual_send;
            $this->allow_automatic_send = (bool) $template->allow_automatic_send;
            $this->include_signature = (bool) ($template->config['include_signature'] ?? true);
        } else {
            $this->channel = request('channel', 'email');
            $this->body_html_template = "<p>Hi {{ client.first_name|there }},</p>\n<p>Your message here...</p>";
            $this->body_text_template = "Hi {{ client.first_name|there }},\n\nYour message here...";
        }
    }

    public function updated($property): void
    {
        if (in_array($property, [
            'channel', 'subject', 'body_html_template', 'body_text_template',
            'default_sender_email_id', 'default_sms_sender_id',
            'include_signature', 'previewClientId',
        ], true)) {
            $this->refreshPreview();
        }
    }

    public function save(TemplateRenderer $renderer)
    {
        $this->authorize($this->template?->exists ? 'templates.edit' : 'templates.create');
        $this->validate();

        $data = [
            'category_id' => $this->category_id,
            'name' => $this->name,
            'key' => $this->key,
            'channel' => MessageChannel::from($this->channel),
            'subject' => $this->channel === 'email' ? $this->subject : null,
            'body_html_template' => $this->channel === 'email' ? $this->body_html_template : null,
            'body_text_template' => $this->body_text_template,
            'default_sender_email_id' => $this->channel === 'email' ? $this->default_sender_email_id : null,
            'default_sms_sender_id' => $this->channel === 'sms' ? $this->default_sms_sender_id : null,
            'applies_to_type' => $this->applies_to_type ?: null,
            'description' => $this->description,
            'is_active' => $this->is_active,
            'allow_manual_send' => $this->allow_manual_send,
            'allow_automatic_send' => $this->allow_automatic_send,
            'config' => [
                'include_signature' => $this->include_signature,
            ],
        ];

        if ($this->template?->exists) {
            $this->template->update($data);
        } else {
            $this->template = ContactTemplate::create($data);
        }

        $this->unknownAtSave = $renderer->validate($this->template);

        session()->flash('template_saved', 'Template saved.');

        if (empty($this->unknownAtSave)) {
            return redirect()->route('templates.edit', $this->template);
        }
    }

    /* ---------- Placeholder insertion ---------- */

    public function insertPlaceholder(string $token, string $target): void
    {
        $snippet = '{{ ' . $token . ' }}';
        match ($target) {
            'subject' => $this->subject = ($this->subject ?? '') . $snippet,
            'html' => $this->body_html_template = ($this->body_html_template ?? '') . $snippet,
            'text' => $this->body_text_template = ($this->body_text_template ?? '') . $snippet,
            default => null,
        };
        $this->refreshPreview();
    }

    /* ---------- Preview ---------- */

    public function refreshPreview(): void
    {
        if (!$this->template && !($this->name && $this->channel)) {
            return;
        }

        // Build an ephemeral template instance for preview so unsaved edits render.
        $preview = $this->template?->exists ? $this->template->replicate() : new ContactTemplate();
        $preview->name = $this->name ?? 'preview';
        $preview->channel = MessageChannel::from($this->channel);
        $preview->subject = $this->subject;
        $preview->body_html_template = $this->body_html_template;
        $preview->body_text_template = $this->body_text_template;
        $preview->config = ['include_signature' => $this->include_signature];

        $sampleClient = $this->resolveSampleClient();
        $sender = $this->resolvePreviewSender();

        $ctx = PlaceholderContext::fromMessageable(
            messageable: $sampleClient,
            solicitor: app(Solicitor::class),
            user: auth()->user(),
            sender: $sender,
        );

        $renderer = app(TemplateRenderer::class);
        $rendered = $renderer->render($preview, $ctx, strict: false);

        $this->previewSubject = $rendered->subject;
        $this->previewBodyText = $rendered->bodyText;
        $this->previewBodyHtml = $rendered->bodyHtml;
        $this->previewPlaceholdersUsed = $rendered->placeholdersUsed;
        $this->previewUnknown = $rendered->unknownPlaceholders;

        if ($preview->isSms()) {
            $seg = $renderer->previewSegments($rendered, MessageChannel::SMS);
            $this->smsLength = $seg['length'];
            $this->smsSegments = $seg['segments'];
            $this->smsEncoding = $seg['encoding'];
        } else {
            $this->smsLength = null;
            $this->smsSegments = null;
            $this->smsEncoding = null;
        }
    }

    private function resolveSampleClient(): ?Client
    {
        if ($this->previewClientId) {
            return Client::with('claim.status')->find($this->previewClientId);
        }
        return Client::with('claim.status')->orderBy('id')->first();
    }

    private function resolvePreviewSender()
    {
        if ($this->channel === 'email') {
            if ($this->default_sender_email_id) {
                return SolicitorEmailSender::find($this->default_sender_email_id);
            }
            return app(Solicitor::class)?->emailSenderFor('general');
        }

        if ($this->default_sms_sender_id) {
            return SolicitorSmsSender::find($this->default_sms_sender_id);
        }
        return SolicitorSmsSender::query()->active()->orderByDesc('is_default')->first();
    }

    /* ---------- Trigger management ---------- */

    public function openTriggerForm(?int $id = null): void
    {
        $this->authorize('communications.triggers.manage');

        $this->showTriggerForm = true;
        $this->editingTriggerId = $id;

        if ($id) {
            $t = ContactTemplateTrigger::findOrFail($id);
            $this->triggerForm = [
                'trigger_type' => $t->trigger_type->value,
                'model_type' => $t->model_type,
                'conditions' => json_encode($t->conditions ?? new \stdClass(), JSON_PRETTY_PRINT),
                'dedupe_window_minutes' => $t->dedupe_window_minutes,
                'is_active' => (bool) $t->is_active,
            ];
        } else {
            $this->triggerForm = [
                'trigger_type' => 'status_changed',
                'model_type' => $this->applies_to_type,
                'conditions' => '{}',
                'dedupe_window_minutes' => 60,
                'is_active' => true,
            ];
        }
    }

    public function cancelTrigger(): void
    {
        $this->showTriggerForm = false;
        $this->editingTriggerId = null;
    }

    public function saveTrigger(): void
    {
        $this->authorize('communications.triggers.manage');

        if (!$this->template?->exists) {
            session()->flash('template_error', 'Save the template before adding triggers.');
            return;
        }

        $decoded = json_decode($this->triggerForm['conditions'] ?: '{}', true);
        if (json_last_error() !== JSON_ERROR_NONE) {
            $this->addError('triggerForm.conditions', 'Conditions must be valid JSON.');
            return;
        }

        $payload = [
            'contact_template_id' => $this->template->id,
            'trigger_type' => TemplateTriggerType::from($this->triggerForm['trigger_type']),
            'model_type' => $this->triggerForm['model_type'] ?: null,
            'conditions' => $decoded ?: null,
            'dedupe_window_minutes' => (int) $this->triggerForm['dedupe_window_minutes'],
            'is_active' => (bool) $this->triggerForm['is_active'],
        ];

        if ($this->editingTriggerId) {
            ContactTemplateTrigger::findOrFail($this->editingTriggerId)->update($payload);
        } else {
            ContactTemplateTrigger::create($payload);
        }

        $this->showTriggerForm = false;
        $this->editingTriggerId = null;
    }

    public function deleteTrigger(int $id): void
    {
        $this->authorize('communications.triggers.manage');
        ContactTemplateTrigger::destroy($id);
    }

    /* ---------- Render ---------- */

    public function render()
    {
        // Ensure preview is fresh for initial render.
        if ($this->previewSubject === null && $this->previewBodyText === null && $this->previewBodyHtml === null) {
            try {
                $this->refreshPreview();
            } catch (\Throwable) {
                // Preview failure must never prevent render() from completing,
                // since render() runs after save() and a throw here would swallow the redirect.
            }
        }

        $placeholders = app(PlaceholderRegistry::class)
            ->availableFor($this->applies_to_type ?: null);

        $placeholdersByPrefix = collect($placeholders)
            ->groupBy(fn ($p) => explode('.', $p->token)[0] ?? 'other');

        $triggers = $this->template?->exists
            ? ContactTemplateTrigger::where('contact_template_id', $this->template->id)
                ->orderByDesc('id')->get()
            : collect();

        $previewClients = Client::query()
            ->orderBy('name_first')
            ->limit(30)
            ->get(['id', 'name_first', 'name_last']);

        return view('components.template.editor', [
            'categories' => ContactCategory::orderBy('name')->get(),
            'emailSenders' => SolicitorEmailSender::orderByDesc('is_default')->get(),
            'smsSenders' => SolicitorSmsSender::query()->active()->orderByDesc('is_default')->orderBy('label')->get(),
            'placeholdersByPrefix' => $placeholdersByPrefix,
            'triggerTypes' => TemplateTriggerType::cases(),
            'triggers' => $triggers,
            'previewClients' => $previewClients,
            'statuses' => Status::query()->orderBy('display_name')->get(['id', 'display_name']),
        ]);
    }
}
