<?php

namespace App\Http\Controllers;

use App\Models\Booking;
use App\Services\BookingStateService;
use App\Services\Calendar\GoogleCalendarService;
use Illuminate\Http\Request;

class BookingActionController extends Controller
{
    public function __construct(private ?GoogleCalendarService $calendar = null)
    {
    }

    public function approve(Booking $booking, BookingStateService $state)
    {
        $this->authorize('update', $booking);
        $state->transition($booking, 'confirmed');
        $this->createCalendarEvent($booking);

        return back()->with('status', 'Booking approved.');
    }

    public function reject(Booking $booking, Request $request, BookingStateService $state)
    {
        $this->authorize('update', $booking);
        $booking->provider_notes = $request->input('reason', 'Rejected');
        $booking->save();
        $state->transition($booking, 'cancelled_by_provider');

        return back()->with('status', 'Booking rejected.');
    }

    public function cancel(Booking $booking, BookingStateService $state)
    {
        $this->authorize('update', $booking);
        $state->transition($booking, 'cancelled_by_customer');
        $this->cancelCalendarEvent($booking);

        return back()->with('status', 'Booking cancelled.');
    }

    public function reschedule(Booking $booking, Request $request, BookingStateService $state)
    {
        $this->authorize('update', $booking);
        $data = $request->validate(['slot_start' => ['required', 'date']]);
        $start = now()->parse($data['slot_start']);
        $booking->scheduled_start = $start;
        $booking->scheduled_end = $booking->service?->duration_minutes ? $start->copy()->addMinutes($booking->service->duration_minutes) : null;
        $booking->status = 'pending_provider_approval';
        $booking->save();
        $state->transition($booking, 'pending_provider_approval');
        $this->cancelCalendarEvent($booking);

        return back()->with('status', 'Reschedule request sent.');
    }

    public function propose(Booking $booking, Request $request, BookingStateService $state)
    {
        $this->authorize('update', $booking);
        $data = $request->validate(['slot_start' => ['required', 'date']]);
        $start = now()->parse($data['slot_start']);
        $booking->meta = array_merge($booking->meta ?? [], ['proposed_start' => $start->toIso8601String()]);
        $booking->save();
        $state->transition($booking, 'pending_provider_approval');
        $this->cancelCalendarEvent($booking);

        return back()->with('status', 'Proposed new time sent to customer.');
    }

    public function acceptProposal(Booking $booking, BookingStateService $state)
    {
        $this->authorize('update', $booking);
        $proposed = data_get($booking->meta, 'proposed_start');
        if ($proposed) {
            $start = now()->parse($proposed);
            $booking->scheduled_start = $start;
            $booking->scheduled_end = $booking->service?->duration_minutes ? $start->copy()->addMinutes($booking->service->duration_minutes) : null;
            $booking->meta = array_merge($booking->meta ?? [], ['proposed_start' => null]);
            $booking->save();
        }
        $state->transition($booking, 'confirmed');
        $this->createCalendarEvent($booking);

        return back()->with('status', 'New time accepted.');
    }

    public function declineProposal(Booking $booking, BookingStateService $state)
    {
        $this->authorize('update', $booking);
        $booking->meta = array_merge($booking->meta ?? [], ['proposed_start' => null]);
        $booking->save();
        $state->transition($booking, 'confirmed');

        return back()->with('status', 'Proposed time declined.');
    }

    protected function cancelCalendarEvent(Booking $booking): void
    {
        if (! $this->calendar || ! $booking->calendar_event_id || ! $booking->provider) {
            return;
        }

        $token = $booking->provider->serviceCalendarTokens()->first();
        if ($token) {
            $this->calendar->cancelEvent($token, $booking->calendar_event_id);
        }
    }

    protected function createCalendarEvent(Booking $booking): void
    {
        if (! $this->calendar || ! $booking->provider || $booking->calendar_event_id) {
            return;
        }

        $token = $booking->provider->serviceCalendarTokens()->first();
        if (! $token) {
            return;
        }

        $created = $this->calendar->createEvent($token, [
            'summary' => 'Booking #'.$booking->id.' - '.$booking->service?->title,
            'description' => 'Customer: '.$booking->customer?->name,
            'start' => [
                'dateTime' => optional($booking->scheduled_start)->toAtomString(),
                'timeZone' => $booking->timezone ?? 'UTC',
            ],
            'end' => [
                'dateTime' => optional($booking->scheduled_end)->toAtomString(),
                'timeZone' => $booking->timezone ?? 'UTC',
            ],
        ]);

        if (is_string($created)) {
            $booking->calendar_event_id = $created;
            $booking->save();
        }
    }
}
