<?php

namespace App\Components\Contact\BulkEmail;

use App\Enum\Contact\BulkEmailCampaignStatus;
use App\Enum\Contact\MessageChannel;
use App\Jobs\Contact\ProcessBulkEmailCampaignJob;
use App\Models\Claim\Status;
use App\Models\Client\Client;
use App\Models\Contact\BulkEmailCampaign;
use App\Models\Contact\ContactTemplate;
use App\Models\Institution\Institution;
use App\Models\LeadSource\LeadSource;
use App\Models\LeadSource\LeadSourceEndpoint;
use App\Models\Solicitor\Solicitor;
use App\Models\Solicitor\SolicitorEmailSender;
use App\Models\Tag;
use App\Models\Tranche;
use App\Models\User\User;
use App\Services\Client\ClientFilter;
use App\Services\Communications\Placeholders\TemplateRenderer;
use App\ValueObjects\Communications\PlaceholderContext;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Livewire\Component;
use Livewire\WithPagination;

class Station extends Component
{
    use AuthorizesRequests, WithPagination;

    /* ---------- filters (names match Client\Index + ClientFilter keys) ---------- */
    public $search = '';
    public array $status_id = [];
    public array $tranche_id = [];
    public array $lead_source_id = [];
    public array $url = [];
    public array $tag_id = [];
    public array $priority = [];
    public $date_from = null;
    public $date_to = null;
    public array $handler = [];
    public array $care_setting_id = [];

    /** Page size for the live matched-recipients list. */
    public int $perPage = 10;

    /* ---------- message selection ---------- */
    public ?int $templateId = null;
    public ?int $senderId = null;

    /* ---------- preview / confirm state ---------- */
    public bool $previewBuilt = false;
    public bool $isUnfiltered = false;
    public bool $confirmedUnfiltered = false;
    public ?int $recipientCount = null;
    public ?string $sampleClientName = null;
    public ?string $sampleSubject = null;
    public ?string $sampleBodyHtml = null;
    public ?string $sampleBodyText = null;

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

    public function mount(): void
    {
        $this->authorize('communications.send.bulk');
    }

    /** Any filter/template/sender change invalidates a built preview. */
    public function updated($prop): void
    {
        if ($prop === 'page') {
            return;
        }

        if ($prop !== 'confirmedUnfiltered') {
            $this->previewBuilt = false;
        }

        // A changed filter (or page size) changes the matched set — go back to page one.
        if (!in_array($prop, ['confirmedUnfiltered', 'templateId', 'senderId'], true)) {
            $this->resetPage();
        }
    }

    public function clearFilters(): void
    {
        $this->reset(
            'search', 'status_id', 'tranche_id', 'lead_source_id', 'url',
            'tag_id', 'priority', 'date_from', 'date_to', 'handler', 'care_setting_id',
        );
        $this->previewBuilt = false;
        $this->resetPage();
    }

    public function buildPreview(): void
    {
        $this->error = null;
        $this->success = null;
        $this->previewBuilt = false;
        $this->confirmedUnfiltered = false;
        $this->sampleClientName = $this->sampleSubject = $this->sampleBodyHtml = $this->sampleBodyText = null;

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

        $query = $this->matchedQuery();

        $this->recipientCount = (clone $query)->count();
        $this->isUnfiltered = collect($this->filters())->filter(fn ($v) => filled($v))->isEmpty();

        $first = (clone $query)->first();
        if ($first) {
            $name = trim(($first->name_first ?? '') . ' ' . ($first->name_last ?? ''));
            $this->sampleClientName = $name !== '' ? $name : ('Client #' . $first->id);

            try {
                $sender = $this->resolveSender($template);
                $ctx = PlaceholderContext::fromMessageable(
                    messageable: $first,
                    solicitor: app(Solicitor::class),
                    user: auth()->user(),
                    sender: $sender,
                );
                $rendered = app(TemplateRenderer::class)->render($template, $ctx, strict: false);
                $this->sampleSubject = $rendered->subject;
                $this->sampleBodyHtml = $rendered->bodyHtml;
                $this->sampleBodyText = $rendered->bodyText;
            } catch (\Throwable $e) {
                $this->error = 'Preview render failed: ' . $e->getMessage();
            }
        }

        $this->previewBuilt = true;
    }

    public function confirmAndSend(): void
    {
        $this->authorize('communications.send.bulk');
        $this->error = null;
        $this->success = null;

        if (!$this->previewBuilt) {
            $this->buildPreview();
            return;
        }

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

        if (!$this->recipientCount) {
            $this->error = 'No clients match the current filter.';
            return;
        }

        if ($this->isUnfiltered && !$this->confirmedUnfiltered) {
            $this->error = 'Tick the confirmation box to email ALL clients.';
            return;
        }

        $campaign = BulkEmailCampaign::create([
            'template_id'      => $template->id,
            'sender_email_id'  => $this->senderId ?: null,
            'filters'          => $this->filters(),
            'total_recipients' => $this->recipientCount,
            'created_by'       => auth()->id(),
            'status'           => BulkEmailCampaignStatus::PENDING,
        ]);

        ProcessBulkEmailCampaignJob::dispatch($campaign->id);

        $this->lastCampaignId = $campaign->id;
        $this->success = 'Campaign queued — sending to ' . number_format($this->recipientCount)
            . ' client(s) in the background.';
        $this->previewBuilt = false;
        $this->confirmedUnfiltered = false;
    }

    public function render()
    {
        $clientMorph = (new Client)->getMorphClass();

        $templates = ContactTemplate::query()
            ->where('is_active', true)
            ->where('allow_manual_send', true)
            ->where('channel', MessageChannel::EMAIL->value)
            ->where(function ($q) use ($clientMorph) {
                $q->whereNull('applies_to_type')
                    ->orWhere('applies_to_type', $clientMorph)
                    ->orWhere('applies_to_type', Client::class);
            })
            ->orderBy('name')
            ->pluck('name', 'id')
            ->toArray();

        $senders = SolicitorEmailSender::query()
            ->orderByDesc('is_default')
            ->get()
            ->mapWithKeys(fn ($s) => [$s->id => $s->label()])
            ->toArray();

        $endpoints = LeadSourceEndpoint::query()
            ->get(['id', 'url', 'display_name'])
            ->mapWithKeys(fn ($e) => [$e->id => "{$e->url} - {$e->display_name}"])
            ->toArray();

        $tranches = Tranche::query()
            ->get(['funder_name', 'tranche_name', 'id'])
            ->mapWithKeys(fn ($t) => [$t->id => "{$t->funder_name} - {$t->tranche_name}"])
            ->toArray();

        $matchedBase = $this->matchedQuery();
        $matchedCount = (clone $matchedBase)->count();
        $noEmailCount = (clone $matchedBase)
            ->where(fn ($q) => $q->whereNull('email_address')->orWhere('email_address', ''))
            ->count();
        $matchedClients = (clone $matchedBase)
            ->with('claim.status')
            ->orderBy('name_last')
            ->orderBy('name_first')
            ->paginate($this->perPage);

        return view('components.contact.bulk-email.station', [
            'templates'    => $templates,
            'senders'      => $senders,
            'leadSources'  => LeadSource::pluck('display_name', 'id')->toArray(),
            'urls'         => [0 => 'None Assigned'] + $endpoints,
            'statuses'     => Status::pluck('display_name', 'id')->toArray(),
            'careSettings' => Institution::orderBy('display_name')->pluck('display_name', 'id')->toArray(),
            'tags'         => Tag::pluck('name', 'id')->toArray(),
            'tranches'     => [0 => 'None Assigned'] + $tranches,
            'handlers'     => User::all()->mapWithKeys(
                fn ($u) => [$u->id => $u->name_first . ' ' . $u->name_last]
            )->toArray(),
            'campaign'       => $this->lastCampaignId ? BulkEmailCampaign::find($this->lastCampaignId) : null,
            'matchedCount'   => $matchedCount,
            'noEmailCount'   => $noEmailCount,
            'matchedClients' => $matchedClients,
        ]);
    }

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

    private function matchedQuery()
    {
        return app(ClientFilter::class)->apply(Client::query(), $this->filters());
    }

    private function filters(): array
    {
        return [
            'search'          => $this->search,
            'status_id'       => $this->status_id,
            'tranche_id'      => $this->tranche_id,
            'lead_source_id'  => $this->lead_source_id,
            'url'             => $this->url,
            'tag_id'          => $this->tag_id,
            'priority'        => $this->priority,
            'date_from'       => $this->date_from,
            'date_to'         => $this->date_to,
            'handler'         => $this->handler,
            'care_setting_id' => $this->care_setting_id,
        ];
    }

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

        return ContactTemplate::query()
            ->where('is_active', true)
            ->where('allow_manual_send', true)
            ->where('channel', MessageChannel::EMAIL->value)
            ->find($this->templateId);
    }

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

        if (!$id) {
            return app(Solicitor::class)?->emailSenderFor('general');
        }

        return SolicitorEmailSender::find($id);
    }
}
