<?php

namespace App\Components\Contact;

use App\Actions\Communications\DispatchContactMessageAction;
use App\Enum\Contact\MessageChannel;
use App\Enum\Contact\MessageOrigin;
use App\Models\Contact\ContactTemplate;
use App\Models\Solicitor\Solicitor;
use App\Models\Solicitor\SolicitorEmailSender;
use App\Models\Solicitor\SolicitorSmsSender;
use App\Services\Communications\Placeholders\TemplateRenderer;
use App\ValueObjects\Communications\DispatchRequest;
use App\ValueObjects\Communications\PlaceholderContext;
use Illuminate\Database\Eloquent\Model;
use Livewire\Attributes\On;
use Livewire\Component;

class ComposeMessage extends Component
{
    public Model $model;

    public bool $open = false;

    /** Filter templates to one channel ('email'|'sms') when opened via channel button. */
    public ?string $channelFilter = null;

    /** When true the panel shows a free-text textarea instead of a template selector. */
    public bool $freeTextMode = false;
    public string $freeSubject = '';
    public string $freeBodyText = '';

    /** When true the rendered preview becomes editable before send. */
    public bool $reviewMode = false;
    public string $reviewSubject = '';
    public string $reviewBodyText = '';

    /** The picked template id (null when none chosen). */
    public ?int $templateId = null;

    /** Override sender — email sender id or phone sender id depending on channel. */
    public ?int $senderId = null;

    /** Computed from template on selection. */
    public ?string $channel = null;

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

    public ?string $error = null;
    public ?string $success = null;

    public function mount(Model $model): void
    {
        $this->model = $model;
    }

    #[On('contact:compose')]
    public function openComposer(?int $templateId = null, ?string $channel = null, bool $freeText = false): void
    {
        $this->resetComposerState();
        $this->channelFilter = $channel;
        $this->open = true;

        if ($freeText) {
            $this->freeTextMode = true;
            return;
        }

        if ($templateId) {
            $this->templateId = (int) $templateId;
            $this->applyTemplateDefaults();
        } elseif ($channel) {
            // Auto-select the first template for this channel so the panel is
            // immediately useful rather than requiring a manual template pick.
            $first = ContactTemplate::query()
                ->where('is_active', true)
                ->where('allow_manual_send', true)
                ->where('channel', $channel)
                ->where(function ($q) {
                    $q->whereNull('applies_to_type')
                      ->orWhere('applies_to_type', $this->model->getMorphClass())
                      ->orWhere('applies_to_type', get_class($this->model));
                })
                ->orderBy('name')
                ->first();

            if ($first) {
                $this->templateId = $first->id;
                $this->applyTemplateDefaults();
            }
        }

        $this->refreshPreview();
    }

    public function switchToFreeText(): void
    {
        $this->freeTextMode = true;
        $this->templateId = null;
        $this->previewSubject = null;
        $this->previewBodyText = null;
        $this->previewBodyHtml = null;
        $this->previewPlaceholders = [];
        $this->previewUnknown = [];
        $this->smsLength = null;
        $this->smsSegments = null;
        $this->smsEncoding = null;
        $this->error = null;
    }

    public function switchToTemplate(): void
    {
        $this->freeTextMode = false;
        $this->freeSubject = '';
        $this->freeBodyText = '';
        $this->smsLength = null;
        $this->smsSegments = null;
        $this->smsEncoding = null;
        $this->error = null;
    }

    public function updatedFreeBodyText(): void
    {
        $this->recalculateFreeTextSms();
    }

    public function enterReviewMode(): void
    {
        $this->reviewMode = true;
        $this->reviewSubject = $this->previewSubject ?? '';
        $this->reviewBodyText = $this->previewBodyText ?? '';
        $this->error = null;

        if ($this->channel === MessageChannel::SMS->value) {
            $this->recalculateReviewSms();
        }
    }

    public function exitReviewMode(): void
    {
        $this->reviewMode = false;
        $this->reviewSubject = '';
        $this->reviewBodyText = '';
        $this->error = null;

        // Restore SMS counter from the original preview
        if ($this->channel === MessageChannel::SMS->value) {
            $renderer = app(TemplateRenderer::class);
            $msg = new \App\ValueObjects\Communications\RenderedMessage(
                subject: null,
                bodyText: $this->previewBodyText ?? '',
                bodyHtml: null,
            );
            $seg = $renderer->previewSegments($msg, MessageChannel::SMS);
            $this->smsLength = $seg['length'];
            $this->smsSegments = $seg['segments'];
            $this->smsEncoding = $seg['encoding'];
        }
    }

    public function updatedReviewBodyText(): void
    {
        $this->recalculateReviewSms();
    }

    public function close(): void
    {
        $this->open = false;
        $this->resetComposerState();
    }

    public function selectTemplate($templateId): void
    {
        $this->templateId = $templateId !== '' && $templateId !== null
            ? (int) $templateId
            : null;
        $this->reviewMode = false;
        $this->reviewSubject = '';
        $this->reviewBodyText = '';
        $this->applyTemplateDefaults();
        $this->refreshPreview();
    }

    public function updatedSenderId(): void
    {
        $this->refreshPreview();
    }

    public function refreshPreview(): void
    {
        $this->error = null;
        $this->previewSubject = null;
        $this->previewBodyText = null;
        $this->previewBodyHtml = null;
        $this->previewPlaceholders = [];
        $this->previewUnknown = [];
        $this->smsLength = null;
        $this->smsSegments = null;
        $this->smsEncoding = null;

        $tpl = $this->currentTemplate();
        if (!$tpl) {
            return;
        }

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

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

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

            if ($tpl->channel === MessageChannel::SMS) {
                $seg = $renderer->previewSegments($rendered, MessageChannel::SMS);
                $this->smsLength = $seg['length'];
                $this->smsSegments = $seg['segments'];
                $this->smsEncoding = $seg['encoding'];
            }
        } catch (\Throwable $e) {
            $this->error = 'Preview failed: ' . $e->getMessage();
        }
    }

    public function send(DispatchContactMessageAction $dispatch): void
    {
        if ($this->freeTextMode) {
            $this->sendFreeText($dispatch);
            return;
        }

        $tpl = $this->currentTemplate();
        if (!$tpl) {
            $this->error = 'Select a template first.';
            return;
        }

        $channel = $tpl->channel;

        $this->authorize($channel === MessageChannel::EMAIL
            ? 'communications.send.email'
            : 'communications.send.sms');

        $request = new DispatchRequest(
            messageable: $this->model,
            template: $tpl,
            user: auth()->user(),
            senderEmailId: $tpl->isEmail() ? $this->senderId : null,
            smsSenderId: $tpl->isSms() ? $this->senderId : null,
            origin: MessageOrigin::MANUAL,
            reviewSubject: $this->reviewMode ? ($this->reviewSubject ?: null) : null,
            reviewBodyText: $this->reviewMode ? $this->reviewBodyText : null,
        );

        $result = $dispatch($request);

        $this->handleDispatchResult($result);
    }

    private function sendFreeText(DispatchContactMessageAction $dispatch): void
    {
        if (!$this->channelFilter) {
            $this->error = 'No channel selected.';
            return;
        }
        if (!trim($this->freeBodyText)) {
            $this->error = 'Message body is required.';
            return;
        }
        if ($this->channelFilter === 'email' && !trim($this->freeSubject)) {
            $this->error = 'Subject is required for email.';
            return;
        }

        $channel = MessageChannel::from($this->channelFilter);

        $this->authorize($channel === MessageChannel::EMAIL
            ? 'communications.send.email'
            : 'communications.send.sms');

        $request = new DispatchRequest(
            messageable: $this->model,
            template: null,
            user: auth()->user(),
            senderEmailId: $channel === MessageChannel::EMAIL ? $this->senderId : null,
            smsSenderId: $channel === MessageChannel::SMS ? $this->senderId : null,
            origin: MessageOrigin::MANUAL,
            channel: $channel,
            freeSubject: $this->freeSubject ?: null,
            freeBodyText: $this->freeBodyText,
        );

        $this->handleDispatchResult($dispatch($request));
    }

    private function handleDispatchResult($result): void
    {
        if ($result->queued) {
            $this->success = 'Message queued for sending.';
            $this->dispatch('contactMessageQueued', messageId: $result->message?->id);
            $this->close();
            return;
        }
        if ($result->wasSuppressed) {
            $this->error = 'Recipient has opted out: ' . ($result->reason ?? '');
            return;
        }
        if ($result->wasDeduped) {
            $this->error = 'Duplicate send prevented: ' . ($result->reason ?? '');
            return;
        }
        if ($result->wasRateLimited) {
            $this->error = 'Rate limit hit — please wait before sending again.';
            return;
        }
        $this->error = $result->reason ?? 'Unable to send.';
    }

    public function render()
    {
        $templates = ContactTemplate::query()
            ->where('is_active', true)
            ->where('allow_manual_send', true)
            ->where(function ($q) {
                $q->whereNull('applies_to_type')
                  ->orWhere('applies_to_type', $this->model->getMorphClass())
                  ->orWhere('applies_to_type', get_class($this->model));
            })
            ->when($this->channelFilter, fn ($q) => $q->where('channel', $this->channelFilter))
            ->orderBy('channel')
            ->orderBy('name')
            ->get();

        $resolvedChannel = $this->freeTextMode ? $this->channelFilter : $this->channel;

        $senders = $resolvedChannel === MessageChannel::SMS->value
            ? SolicitorSmsSender::query()->active()->orderByDesc('is_default')->orderBy('label')->get()
            : SolicitorEmailSender::query()->orderByDesc('is_default')->get();

        return view('components.contact.compose-message', [
            'templates' => $templates,
            'senders' => $senders,
            'currentTemplate' => $this->currentTemplate(),
        ]);
    }

    /* ---------- helpers ---------- */

    private function resetComposerState(): void
    {
        $this->channelFilter = null;
        $this->freeTextMode = false;
        $this->freeSubject = '';
        $this->freeBodyText = '';
        $this->reviewMode = false;
        $this->reviewSubject = '';
        $this->reviewBodyText = '';
        $this->templateId = null;
        $this->senderId = null;
        $this->channel = null;
        $this->previewSubject = null;
        $this->previewBodyText = null;
        $this->previewBodyHtml = null;
        $this->previewPlaceholders = [];
        $this->previewUnknown = [];
        $this->smsLength = null;
        $this->smsSegments = null;
        $this->smsEncoding = null;
        $this->error = null;
        $this->success = null;
    }

    private function recalculateReviewSms(): void
    {
        $this->smsLength = null;
        $this->smsSegments = null;
        $this->smsEncoding = null;

        if ($this->channel !== MessageChannel::SMS->value || $this->reviewBodyText === '') {
            return;
        }

        $renderer = app(TemplateRenderer::class);
        $msg = new \App\ValueObjects\Communications\RenderedMessage(
            subject: null,
            bodyText: $this->reviewBodyText,
            bodyHtml: null,
        );
        $seg = $renderer->previewSegments($msg, MessageChannel::SMS);
        $this->smsLength = $seg['length'];
        $this->smsSegments = $seg['segments'];
        $this->smsEncoding = $seg['encoding'];
    }

    private function recalculateFreeTextSms(): void
    {
        $this->smsLength = null;
        $this->smsSegments = null;
        $this->smsEncoding = null;

        if ($this->channelFilter !== 'sms' || $this->freeBodyText === '') {
            return;
        }

        $renderer = app(TemplateRenderer::class);
        $msg = new \App\ValueObjects\Communications\RenderedMessage(
            subject: null,
            bodyText: $this->freeBodyText,
            bodyHtml: null,
        );
        $seg = $renderer->previewSegments($msg, MessageChannel::SMS);
        $this->smsLength = $seg['length'];
        $this->smsSegments = $seg['segments'];
        $this->smsEncoding = $seg['encoding'];
    }

    private function applyTemplateDefaults(): void
    {
        $tpl = $this->currentTemplate();
        if (!$tpl) {
            return;
        }
        $this->channel = $tpl->channel?->value;
        $this->senderId = $tpl->isEmail()
            ? $tpl->default_sender_email_id
            : $tpl->default_sms_sender_id;
    }

    private function currentTemplate(): ?ContactTemplate
    {
        return $this->templateId ? ContactTemplate::find($this->templateId) : null;
    }

    private function resolveSender(ContactTemplate $tpl)
    {
        $id = $this->senderId
            ?: ($tpl->isEmail() ? $tpl->default_sender_email_id : $tpl->default_sms_sender_id);

        if (!$id) {
            return $tpl->isEmail()
                ? app(Solicitor::class)?->emailSenderFor('general')
                : SolicitorSmsSender::query()->active()->orderByDesc('is_default')->first();
        }

        return $tpl->isEmail()
            ? SolicitorEmailSender::find($id)
            : SolicitorSmsSender::find($id);
    }
}
