<?php

declare(strict_types=1);

namespace App\Services;

use App\Core\Logger;
use App\Models\IntegrationModel;

/**
 * GoogleCalendarClient
 *
 * Pushes A&B Hub appointments to Google Calendar as real events, and
 * tracks the resulting event id on appointments.google_calendar_event_id
 * for update/delete round-trips. Access-token refresh is handled here
 * transparently via GoogleOAuthService so callers never have to think
 * about token expiry.
 */
final class GoogleCalendarClient
{
    private const API_BASE = 'https://www.googleapis.com/calendar/v3';

    public function __construct(
        private readonly IntegrationModel $integrations = new IntegrationModel(),
        private readonly GoogleOAuthService $oauth = new GoogleOAuthService()
    ) {
    }

    public function isConfigured(): bool
    {
        $creds = $this->integrations->credentialsFor('google_calendar');

        return $creds !== null && !empty($creds['access_token']);
    }

    /** @return array{success:bool, event_id?:string, error?:string} */
    public function createEvent(string $summary, string $description, string $startDateTime, string $endDateTime, string $timezone = 'America/Toronto'): array
    {
        return $this->request('POST', '/calendars/primary/events', [
            'summary' => $summary,
            'description' => $description,
            'start' => ['dateTime' => $this->toRfc3339($startDateTime), 'timeZone' => $timezone],
            'end' => ['dateTime' => $this->toRfc3339($endDateTime), 'timeZone' => $timezone],
        ]);
    }

    public function updateEvent(string $eventId, string $startDateTime, string $endDateTime, string $timezone = 'America/Toronto'): array
    {
        return $this->request('PATCH', "/calendars/primary/events/{$eventId}", [
            'start' => ['dateTime' => $this->toRfc3339($startDateTime), 'timeZone' => $timezone],
            'end' => ['dateTime' => $this->toRfc3339($endDateTime), 'timeZone' => $timezone],
        ]);
    }

    public function deleteEvent(string $eventId): array
    {
        return $this->request('DELETE', "/calendars/primary/events/{$eventId}");
    }

    private function toRfc3339(string $mysqlDateTime): string
    {
        return (new \DateTimeImmutable($mysqlDateTime))->format(\DateTimeInterface::RFC3339);
    }

    private function request(string $method, string $path, ?array $body = null): array
    {
        $creds = $this->integrations->credentialsFor('google_calendar');
        if ($creds === null || empty($creds['access_token'])) {
            return ['success' => false, 'error' => 'Google Calendar is not connected. Configure it from Admin > Integrations.'];
        }

        if (!empty($creds['expires_at']) && strtotime($creds['expires_at']) < time() && !empty($creds['refresh_token'])) {
            $refreshed = $this->oauth->refreshAccessToken('google_calendar', $creds['refresh_token']);
            if ($refreshed['success']) {
                $creds['access_token'] = $refreshed['access_token'];
                $this->integrations->connect('google_calendar', array_merge($creds, ['access_token' => $refreshed['access_token'], 'expires_at' => $refreshed['expires_at']]), 0);
            }
        }

        if (!function_exists('curl_init')) {
            return ['success' => false, 'error' => 'Server is missing the PHP curl extension.'];
        }

        $ch = curl_init(self::API_BASE . $path);
        $options = [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_CUSTOMREQUEST => $method,
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/json',
                'Authorization: Bearer ' . $creds['access_token'],
            ],
            CURLOPT_TIMEOUT => 20,
        ];
        if ($body !== null) {
            $options[CURLOPT_POSTFIELDS] = json_encode($body);
        }
        curl_setopt_array($ch, $options);

        $responseBody = curl_exec($ch);
        $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);

        if ($responseBody === false || $error !== '') {
            Logger::error('GoogleCalendarClient: request failed', ['error' => $error]);

            return ['success' => false, 'error' => "Could not reach Google Calendar: {$error}"];
        }

        if ($status >= 300) {
            $decoded = json_decode((string) $responseBody, true);
            $apiError = $decoded['error']['message'] ?? "HTTP {$status}";
            Logger::error('GoogleCalendarClient: API error', ['status' => $status, 'error' => $apiError]);

            return ['success' => false, 'error' => $apiError];
        }

        $decoded = json_decode((string) $responseBody, true);

        return ['success' => true, 'event_id' => $decoded['id'] ?? null];
    }
}
