<?php

namespace App\Livewire\Calendar\Forms;

use Livewire\Component;
use App\Models\Event;
use Carbon\Carbon;
use Carbon\CarbonPeriod;

class EventForm extends Component
{
    public $eventId;

    public $title;
    public $starts_at;

    public $start_time;
    public $end_time;

    public $is_all_day = false;
    public $is_multi_day = false;

    public $multi_start_date;
    public $multi_end_date;

    public $exceptions = [];

    public $color = '#6366f1';

    public array $reminders = [];

    public string $customReminderTime = '';
    public string $customReminderType = 'time_of_day';

    public $attendeeSearch = '';
    public $attendeeSuggestions = [];
    public $attendees = [];

    public $notes;

    public $recurrence = null;
    public $recurrence_end_date = null;

    protected $listeners = [
        'eventForm:save' => 'save',
        'eventForm:delete' => 'delete',
    ];

    public function mount($eventId = null, $starts_at = null, $time = null)
    {
        $this->eventId = $eventId;
        $this->starts_at = $starts_at;

        $tz = auth()->user()->timezone ?? config('app.timezone');

        if (!$eventId && $time) {
            $this->start_time = $time;
            [$h, $m] = array_map('intval', explode(':', $time));
            $endCarbon = Carbon::createFromTime($h, $m)->addHour();
            $this->end_time = $endCarbon->format('H:i');
        }

        if ($eventId) {

            $event = Event::with('contacts')->findOrFail($eventId);

            $this->title = $event->title;

            $activeDate = $starts_at
                ? Carbon::parse($starts_at, $tz)
                : $event->starts_at->copy()->timezone($tz);

            $this->starts_at = $activeDate->format('Y-m-d');

            $display = $event->getDisplayTimeForDate($this->starts_at, $tz);

            $this->start_time = $display['start']?->format('H:i');
            $this->end_time   = $display['end']?->format('H:i');

            $this->is_all_day           = $event->is_all_day;
            $this->color                = $event->color;
            $this->notes                = $event->notes;
            $this->recurrence           = $event->recurrence;
            $this->recurrence_end_date  = $event->recurrence_end_date?->format('Y-m-d');

            $this->reminders = $event->reminders ?? [];

            $this->attendees = $event->contacts->map(fn($c) => [
                'id'   => $c->id,
                'name' => $c->name,
            ])->values()->toArray();

            if ($event->ends_at && !$event->starts_at->isSameDay($event->ends_at)) {
                $this->is_multi_day = true;

                $this->multi_start_date = $event->starts_at
                    ->timezone($tz)
                    ->format('Y-m-d');

                $this->multi_end_date = $event->ends_at
                    ->timezone($tz)
                    ->format('Y-m-d');
            }

            $this->exceptions = collect($event->exceptions ?? [])
                ->keyBy('date')
                ->toArray();
        }
    }

    public function getDaysProperty()
    {
        if (!$this->is_multi_day) return collect();

        return collect(
            CarbonPeriod::create($this->multi_start_date, $this->multi_end_date)
        );
    }

    public function updatedIsMultiDay($value)
    {
        if ($value && $this->starts_at) {
            $this->multi_start_date = $this->starts_at;
            $this->multi_end_date   = Carbon::parse($this->starts_at)->addDay()->format('Y-m-d');
        }
    }

    public function updatedAttendeeSearch($value)
    {
        if (strlen(trim($value)) < 1) {
            $this->attendeeSuggestions = [];
            return;
        }

        $selectedIds = array_column($this->attendees, 'id');

        $this->attendeeSuggestions = auth()->user()
            ->contacts()
            ->where(function ($q) use ($value) {
                $q->where('name', 'like', "%{$value}%")
                  ->orWhere('email', 'like', "%{$value}%");
            })
            ->whereNotIn('id', $selectedIds)
            ->limit(6)
            ->get(['id', 'name'])
            ->toArray();
    }

    public function addAttendee(string $id, string $name): void
    {
        $alreadyAdded = collect($this->attendees)->contains('id', $id);
        if (!$alreadyAdded) {
            $this->attendees[] = ['id' => $id, 'name' => $name];
        }
        $this->attendeeSearch = '';
        $this->attendeeSuggestions = [];
    }

    public function removeAttendee(string $id): void
    {
        $this->attendees = array_values(
            array_filter($this->attendees, fn($a) => $a['id'] !== $id)
        );
    }

    public function addCustomReminder(): void
    {
        if (empty($this->customReminderTime)) return;

        $type = $this->customReminderType ?: 'time_of_day';
        $time = $this->localTimeToUtc($this->customReminderTime);

        $this->reminders[] = ['type' => $type, 'time' => $time];

        $this->customReminderTime = '';
        $this->customReminderType = 'time_of_day';
    }

    public function addReminder(string $type, ?int $minutes = null, ?string $time = null): void
    {
        if ($time !== null && in_array($type, ['time_of_day', 'day_before'])) {
            $time = $this->localTimeToUtc($time);
        }

        $this->reminders[] = array_filter([
            'type'    => $type,
            'minutes' => $minutes,
            'time'    => $time,
        ], fn($v) => $v !== null);
    }

    private function localTimeToUtc(string $localTime): string
    {
        $tz = auth()->user()->timezone ?? 'UTC';
        return \Carbon\Carbon::createFromFormat('H:i', $localTime, $tz)->utc()->format('H:i');
    }

    public function removeReminder(int $i): void
    {
        array_splice($this->reminders, $i, 1);
    }

    public function toggleException($date)
    {
        if (isset($this->exceptions[$date])) {
            unset($this->exceptions[$date]);
        } else {
            $this->exceptions[$date] = [
                'start' => $this->start_time,
                'end'   => $this->end_time,
            ];
        }
    }

    public function delete()
    {
        if (!$this->eventId) return;

        $event = Event::where('id', $this->eventId)
            ->where('user_id', auth()->id())
            ->first();

        if ($event) {
            $event->contacts()->detach();
            $event->users()->detach();
            $event->delete();
        }

        $this->dispatch('eventCreated');
        $this->dispatch('sidebar:close');
    }

    public function save()
    {
        $tz = auth()->user()->timezone ?? 'UTC';

        $start = Carbon::createFromFormat(
            'Y-m-d H:i',
            $this->starts_at . ' ' . ($this->start_time ?? '00:00'),
            $tz
        )->utc();

        $end = $this->end_time
            ? Carbon::createFromFormat('Y-m-d H:i', $this->starts_at . ' ' . $this->end_time, $tz)->utc()
            : ($this->is_all_day
                ? Carbon::createFromFormat('Y-m-d', $this->starts_at, $tz)->endOfDay()->utc()
                : null);

        if ($this->is_multi_day) {

            $start = Carbon::createFromFormat(
                'Y-m-d H:i',
                $this->multi_start_date . ' ' . ($this->start_time ?? '00:00'),
                $tz
            )->utc();

            $end = $this->multi_end_date
                ? Carbon::createFromFormat(
                    'Y-m-d H:i',
                    $this->multi_end_date . ' ' . ($this->end_time ?? '23:59'),
                    $tz
                )->utc()
                : null;
        }

        $exceptions = collect($this->exceptions)
            ->map(fn($e, $date) => [
                'date' => $date,
                'start' => $e['start'] ?? null,
                'end' => $e['end'] ?? null,
            ])
            ->values()
            ->toArray();

        $event = Event::updateOrCreate(
            ['id' => $this->eventId],
            [
                'user_id'              => auth()->id(),
                'title'                => $this->title,
                'starts_at'            => $start,
                'ends_at'              => $end,
                'is_all_day'           => $this->is_all_day,
                'color'                => $this->color,
                'notes'                => $this->notes,
                'exceptions'           => $exceptions,
                'reminders'            => $this->reminders,
                'recurrence'           => $this->recurrence ?: null,
                'recurrence_end_date'  => $this->recurrence ? ($this->recurrence_end_date ?: null) : null,
            ]
        );

        $attendeeIds = array_column($this->attendees, 'id');
        $event->contacts()->sync($attendeeIds);

        $this->dispatch('eventCreated');
        $this->dispatch('sidebar:close');
    }

    public function render()
    {
        return view('livewire.calendar.forms.event-form');
    }
}
