<?php

namespace App\Services\Calendar;

use App\Models\ServiceCalendarToken;
use Carbon\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class GoogleCalendarService
{
    /**
     * Fetch busy slots from Google Calendar.
     * Returns empty collection if tokens/config are missing.
     */
    public function fetchBusySlots(ServiceCalendarToken $token, Carbon $from, Carbon $to): Collection
    {
        if (! config('services.google.client_id') || ! $token->access_token['access_token'] ?? null) {
            return collect();
        }

        $token = $this->ensureValidToken($token);

        $calendarId = $token->remote_calendar_id ?: 'primary';
        $response = Http::withToken($token->access_token['access_token'])
            ->post('https://www.googleapis.com/calendar/v3/freeBusy', [
                'timeMin' => $from->toAtomString(),
                'timeMax' => $to->toAtomString(),
                'items' => [['id' => $calendarId]],
            ]);

        if ($response->failed()) {
            Log::warning('Google freeBusy failed', ['body' => $response->body()]);
            return collect();
        }

        $busy = collect(data_get($response->json(), "calendars.$calendarId.busy", []));

        return $busy->map(function ($item) {
            return [
                'start' => Carbon::parse($item['start']),
                'end' => Carbon::parse($item['end']),
            ];
        });
    }

    /**
     * Exchange authorization code for tokens. Implement with Google_Client / Socialite.
     */
    public function exchangeAuthCode(string $code): array
    {
        $clientId = config('services.google.client_id');
        $clientSecret = config('services.google.client_secret');
        $redirect = config('services.google.redirect');

        if (! $clientId || ! $clientSecret || ! $redirect) {
            return [];
        }

        $response = Http::asForm()->post('https://oauth2.googleapis.com/token', [
            'code' => $code,
            'client_id' => $clientId,
            'client_secret' => $clientSecret,
            'redirect_uri' => $redirect,
            'grant_type' => 'authorization_code',
        ]);

        if ($response->failed()) {
            Log::warning('Google token exchange failed', ['body' => $response->body()]);
            return [];
        }

        $data = $response->json();
        $data['expires_at'] = isset($data['expires_in']) ? now()->addSeconds($data['expires_in']) : null;

        return $data;
    }

    public function buildAuthUrl(): ?string
    {
        $clientId = config('services.google.client_id');
        $redirect = config('services.google.redirect');

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

        $params = http_build_query([
            'response_type' => 'code',
            'client_id' => $clientId,
            'redirect_uri' => $redirect,
            'scope' => implode(' ', [
                'https://www.googleapis.com/auth/calendar.readonly',
                'https://www.googleapis.com/auth/calendar.events',
            ]),
            'access_type' => 'offline',
            'prompt' => 'consent',
            'include_granted_scopes' => 'true',
        ]);

        return "https://accounts.google.com/o/oauth2/v2/auth?{$params}";
    }

    protected function ensureValidToken(ServiceCalendarToken $token): ServiceCalendarToken
    {
        $expiresAt = $token->expires_at;
        if ($expiresAt && $expiresAt->isFuture()) {
            return $token;
        }

        if (! $token->refresh_token) {
            return $token;
        }

        $clientId = config('services.google.client_id');
        $clientSecret = config('services.google.client_secret');
        $response = Http::asForm()->post('https://oauth2.googleapis.com/token', [
            'grant_type' => 'refresh_token',
            'refresh_token' => $token->refresh_token,
            'client_id' => $clientId,
            'client_secret' => $clientSecret,
        ]);

        if ($response->successful()) {
            $data = $response->json();
            $token->access_token = [
                'access_token' => $data['access_token'] ?? null,
                'token_type' => $data['token_type'] ?? 'Bearer',
            ];
            $token->expires_at = isset($data['expires_in']) ? now()->addSeconds($data['expires_in']) : null;
            $token->save();
        }

        return $token;
    }

    /**
     * Create a calendar event when a booking is confirmed. Stubbed to no-op if tokens/config missing.
     */
    public function createEvent(ServiceCalendarToken $token, array $event): bool|string
    {
        if (! config('services.google.client_id') || ! ($token->access_token['access_token'] ?? null)) {
            return false;
        }

        $token = $this->ensureValidToken($token);
        $calendarId = $token->remote_calendar_id ?: 'primary';

        $response = Http::withToken($token->access_token['access_token'])
            ->post("https://www.googleapis.com/calendar/v3/calendars/{$calendarId}/events", $event);

        if ($response->failed()) {
            Log::warning('Google create event failed', ['body' => $response->body()]);
            return false;
        }

        return data_get($response->json(), 'id') ?: true;
    }

    /**
     * Delete/cancel an event by ID.
     */
    public function cancelEvent(ServiceCalendarToken $token, string $eventId): bool
    {
        if (! ($token->access_token['access_token'] ?? null)) {
            return false;
        }

        $token = $this->ensureValidToken($token);
        $calendarId = $token->remote_calendar_id ?: 'primary';

        $response = Http::withToken($token->access_token['access_token'])
            ->delete("https://www.googleapis.com/calendar/v3/calendars/{$calendarId}/events/{$eventId}");

        if ($response->failed()) {
            Log::warning('Google delete event failed', ['body' => $response->body()]);
            return false;
        }

        return true;
    }
}
