<?php

namespace App\Http\Livewire;

use Livewire\Component;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;

use App\Http\Middleware\TenantMiddleware;
use App\Models\SmsMessage;
use App\Models\Member;

class SmsComunications extends Component
{
    public ?int $messageId = null;
    public string $subject = '';
    public string $content = '';

    public array $recipients = [];

    public string $mode = 'now'; // 'now' | 'schedule'
    public ?string $schedule_at = null;
    public ?string $timezone = 'UTC';

    public $records;
    public $categories;
    public $courses;

    public bool $showForm = false;
    public bool $locked = false;

    public $success;
    public $error;

    public function boot()
    {
        app(TenantMiddleware::class)->setupTenantConnection();
    }

    public function mount()
    {
        if (auth()->user()?->level != env('LEVEL_ADMIN', 0)) {
            return redirect()->to('/dashboard');
        }

        $this->categories = [];
        $this->getCategories(\App\Models\Category::select('id', 'name')->where('parent_id', null)->orderBy('name')->get(), 0);

        $this->courses = [];
        $this->getCourses(\App\Models\Course::select('id', 'name')->where('parent_id', null)->orderBy('name', 'ASC')->get(), 0);

        $this->schedule_at = now($this->timezone)->addHour()->format('Y-m-d\TH:i');
    }

    public function render()
    {
        if (!$this->showForm) {
            $this->records = SmsMessage::withCount(['recipients'])
                ->orderBy('created_at', 'desc')
                ->get();
        } else {
            $this->categories = [];
            $this->getCategories(\App\Models\Category::select('id', 'name')->where('parent_id', null)->orderBy('name')->get(), 0);

            $this->courses = [];
            $this->getCourses(\App\Models\Course::select('id', 'name')->where('parent_id', null)->orderBy('name', 'ASC')->get(), 0);
        }

        return view('livewire.sms_comunications');
    }

    protected function baseRules(): array
    {
        return [
            'subject' => 'required|string|max:255',
            'content' => 'required|string|max:900',
            'recipients' => 'required|array|min:1',
            'recipients.*.phone' => 'required|string',
        ];
    }

    protected function baseMessages(): array
    {
        return [
            'subject.*' => 'Il campo nome template è richiesto',
            'content.max' => 'Il messaggio non può essere più lungo di 900 caratteri',
            'content.*' => 'Il messaggio è richiesto',
            'recipients.*' => 'Selezionare almeno un destinatario',
            'schedule_at.after' => 'La data di invio deve essere nel futuro',
            'schedule_at.*' => 'Il campo data è richiesto',
        ];
    }

    protected function validateDraft(): void
    {
        $rules = [];
        // $rules = $this->baseRules();
        $rules['subject'] = 'required|string|max:255';
        $this->validate($rules, $this->baseMessages());
    }

    protected function validateSend(): void
    {
        $this->validate($this->baseRules(), $this->baseMessages());
    }

    protected function validateSchedule(): void
    {
        $rules = $this->baseRules();
        $rules['schedule_at'] = 'required|date|after:now';
        $this->validate($rules, $this->baseMessages());
    }

    public function add()
    {
        $this->reset(['messageId', 'subject', 'content', 'recipients', 'mode', 'schedule_at']);
        $this->mode = 'now';
        $this->schedule_at = now($this->timezone)->addHour()->format('Y-m-d\TH:i');

        $this->showForm = true;

        $this->dispatchBrowserEvent('init-recipients-table', [
            'selected' => collect($this->recipients)->pluck('member_id')->filter()->values()->all(),
        ]);
    }

    public function edit($id)
    {
        try {
            $msg = SmsMessage::with(['recipients'])->findOrFail($id);

            $this->messageId = $msg->id;
            $this->subject = $msg->subject;
            $this->content = $msg->content;
            $this->recipients = $msg->recipients->map(fn($r) => [
                'member_id' => $r->member_id,
                'phone' => $r->phone,
                'first_name'    => optional($r->member)->first_name,
                'last_name'     => optional($r->member)->last_name,
            ])->toArray();
            $this->mode = $msg->status === 'scheduled' ? 'schedule' : 'now';
            $this->schedule_at = optional($msg->schedule_at)?->setTimezone($this->timezone)?->format('Y-m-d\TH:i');

            $this->showForm = true;
            $this->locked = $msg->isLocked();

            $this->dispatchBrowserEvent('init-recipients-table', [
                'selected' => collect($this->recipients)->pluck('member_id')->filter()->values()->all(),
            ]);
        } catch (\Throwable $ex) {
            $this->error = 'Errore (' . $ex->getMessage() . ')';
        }
    }


    public function duplicate($id, $withRecipients = true)
    {
        try {
            $copy = SmsMessage::with(['recipients'])->findOrFail($id)->duplicate($withRecipients);
            $this->edit($copy->id);
            $this->success = 'Bozza duplicata';
        } catch (\Throwable $ex) {
            $this->error = 'Errore (' . $ex->getMessage() . ')';
        }
    }

    public function saveDraft()
    {
        $this->validateDraft();

        DB::transaction(function () {
            $msg = $this->upsertMessage(status: 'draft', scheduleAt: null);
            $this->upsertRecipients($msg);
            $this->messageId = $msg->id;
            $this->locked = $msg->isLocked();
        });

        $this->success = 'Bozza salvata';

        $this->dispatchBrowserEvent('scroll-top');
    }

    public function sendNow()
    {
        $this->validateSend();

        if ($this->messageId) {
            $existing = SmsMessage::findOrFail($this->messageId);
            if ($existing->isLocked()) {
                $this->error = 'Questo sms è già in invio o inviato e non può essere modificato.';
                return;
            }
        }

        DB::transaction(function () {
            $msg = $this->upsertMessage(status: 'processing', scheduleAt: null);
            $this->upsertRecipients($msg, true);
            $this->messageId = $msg->id;
            $this->locked = true;
        });

        dispatch(new \App\Jobs\SendSmsMessage($this->messageId));
        $this->success = 'Invio avviato';

        $this->dispatchBrowserEvent('scroll-top');
    }

    public function scheduleMessage()
    {
        $this->validateSchedule();

        if ($this->messageId) {
            $existing = SmsMessage::findOrFail($this->messageId);
            if ($existing->isLocked()) {
                $this->error = 'Questo sms è già in invio o inviato e non può essere modificato.';
                return;
            }
        }

        $scheduledAt = \Carbon\Carbon::parse($this->schedule_at, $this->timezone)->setTimezone('UTC');

        DB::transaction(function () use ($scheduledAt) {
            $msg = $this->upsertMessage(status: 'scheduled', scheduleAt: $scheduledAt);
            $this->upsertRecipients($msg, true);
            $this->messageId = $msg->id;
            $this->locked = $msg->isLocked();
        });

        $this->success = 'Sms programmato';

        $this->dispatchBrowserEvent('scroll-top');
    }

    protected function upsertMessage(string $status, $scheduleAt): SmsMessage
    {
        return SmsMessage::updateOrCreate(
            ['id' => $this->messageId],
            [
                'subject' => $this->subject,
                'content' => $this->content,
                'status' => $status,
                'schedule_at' => $scheduleAt,
                'created_by'   => auth()->id(),
            ]
        );
    }

    protected function upsertRecipients(SmsMessage $msg, bool $force = false): void
    {
        if (!$force && $msg->isLocked()) return;

        $msg->recipients()->delete();

        $rows = collect($this->recipients)->map(fn($r) => [
            'sms_message_id' => $msg->id,
            'member_id' => $r['member_id'] ?? null,
            'phone' => $r['phone'],
            'status' => 'pending',
            'created_at' => now(),
            'updated_at' => now(),
        ])->values()->all();

        if ($rows) \App\Models\SmsMessageRecipient::insert($rows);
    }

    public function cancel()
    {
        $this->showForm = false;
        $this->reset(['messageId', 'subject', 'content', 'recipients', 'mode', 'schedule_at']);
        $this->mode = 'now';
        $this->schedule_at = now($this->timezone)->addHour()->format('Y-m-d\TH:i');

        $this->dispatchBrowserEvent('init-archive-table');
    }

    public function getCategories($records, $indentation)
    {
        foreach ($records as $record) {
            $this->categories[] = array('id' => $record->id, 'name' => $record->getTree());
            if (count($record->childs))
                $this->getCategories($record->childs, $indentation + 1);
        }
    }

    public function getCourses($records, $indentation)
    {
        /** @var \App\Models\Course $record */
        foreach ($records as $record) {
            $this->courses[] = array('id' => $record->id, 'name' => $record->getTree());
            if (count($record->childs))
                $this->getCourses($record->childs, $indentation + 1);
        }
    }

    public function toggleRecipient($id)
    {
        $id = (int)$id;

        $idx = collect($this->recipients)->search(fn($r) => (int)($r['member_id'] ?? 0) === $id);
        if ($idx !== false) {
            array_splice($this->recipients, $idx, 1);
            return;
        }

        $m = Member::select('id', 'phone', 'first_name', 'last_name')->find($id);
        if (!$m || empty($m->phone)) return;

        $this->recipients[] = [
            'member_id' => $m->id,
            'phone' => $m->phone,
            'first_name' => $m->first_name,
            'last_name' => $m->last_name,
        ];
    }

    public function deleteMessage(int $id)
    {
        $msg = \App\Models\SmsMessage::findOrFail($id);

        if (! in_array($msg->status, ['draft', 'failed'], true)) {
            return;
        }

        $msg->delete();

        $this->dispatchBrowserEvent('sms-deleted', ['id' => $id]);
    }
}
