<?php

namespace App\Services\Meet\Calendar;

use App\Models\CalendarConnection;
use App\Models\Room;
use App\Models\User;
use Illuminate\Support\Facades\Http;

class MicrosoftCalendarProvider
{
    public function authorizeUrl(): ?string
    {
        $clientId = config('meet.calendar.microsoft.client_id');
        $redirect = config('meet.calendar.microsoft.redirect');
        $tenant = config('meet.calendar.microsoft.tenant', 'common');

        if (! $clientId || ! $redirect) {
            return null;
        }

        $params = http_build_query([
            'client_id' => $clientId,
            'redirect_uri' => $redirect,
            'response_type' => 'code',
            'scope' => 'offline_access Calendars.ReadWrite',
            'response_mode' => 'query',
        ]);

        return "https://login.microsoftonline.com/{$tenant}/oauth2/v2.0/authorize?{$params}";
    }

    /**
     * @return array<string, mixed>|null
     */
    public function exchangeCode(string $code): ?array
    {
        $tenant = config('meet.calendar.microsoft.tenant', 'common');

        $response = Http::asForm()->post("https://login.microsoftonline.com/{$tenant}/oauth2/v2.0/token", [
            'code' => $code,
            'client_id' => config('meet.calendar.microsoft.client_id'),
            'client_secret' => config('meet.calendar.microsoft.client_secret'),
            'redirect_uri' => config('meet.calendar.microsoft.redirect'),
            'grant_type' => 'authorization_code',
        ]);

        return $response->successful() ? $response->json() : null;
    }

    public function createEvent(CalendarConnection $connection, Room $room, User $host): ?string
    {
        if (! $connection->access_token) {
            return null;
        }

        $response = Http::withToken($connection->access_token)->post(
            'https://graph.microsoft.com/v1.0/me/events',
            $this->eventPayload($room, $host),
        );

        return $response->successful() ? $response->json('id') : null;
    }

    public function updateEvent(CalendarConnection $connection, Room $room, User $host): bool
    {
        if (! $connection->access_token || ! $room->calendar_event_id) {
            return false;
        }

        return Http::withToken($connection->access_token)->patch(
            'https://graph.microsoft.com/v1.0/me/events/'.$room->calendar_event_id,
            $this->eventPayload($room, $host),
        )->successful();
    }

    public function deleteEvent(CalendarConnection $connection, Room $room): bool
    {
        if (! $connection->access_token || ! $room->calendar_event_id) {
            return false;
        }

        return Http::withToken($connection->access_token)->delete(
            'https://graph.microsoft.com/v1.0/me/events/'.$room->calendar_event_id,
        )->successful();
    }

    /** @return array<string, mixed> */
    protected function eventPayload(Room $room, User $host): array
    {
        $start = ($room->scheduled_at ?? now())->toIso8601String();
        $end = ($room->scheduled_at ?? now())->addMinutes($room->duration_minutes ?? 60)->toIso8601String();

        return [
            'subject' => $room->title,
            'body' => [
                'contentType' => 'Text',
                'content' => trim(($room->description ?? '')."\n\nJoin: ".$room->joinUrl()),
            ],
            'start' => ['dateTime' => $start, 'timeZone' => $room->timezone],
            'end' => ['dateTime' => $end, 'timeZone' => $room->timezone],
            'location' => ['displayName' => $room->joinUrl()],
            'organizer' => ['emailAddress' => ['address' => $host->email, 'name' => $host->name]],
        ];
    }
}
