<?php
/**
 * Google Calendar Service
 *
 * Proxies all Google Calendar operations through the BoostBot centralized backend.
 * No OAuth credentials are stored locally — the backend manages tokens securely.
 *
 * @package BoostBot
 * @since   1.0.0
 * @updated 1.10.0 — Migrated from direct Google API to backend proxy
 */

// Prevent direct access.
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/**
 * Class BoostBot_Google_Calendar_Service
 *
 * Proxies Google Calendar operations through the centralized backend.
 */
class BoostBot_Google_Calendar_Service {

    /**
     * Option name for local cache of connection status.
     */
    const STATUS_CACHE_OPTION = 'boostbot_google_calendar_status_cache';

    /**
     * Backend client instance.
     *
     * @var BoostBot_Credits_Backend_Client
     */
    private $backend;

    /**
     * Site ID on the backend.
     *
     * @var string|null
     */
    private $site_id;

    /**
     * Constructor.
     */
    public function __construct() {
        $this->backend = new BoostBot_Credits_Backend_Client();
        $site_id = (string) BoostBot_Settings::get( 'backend_site_id', '' );
        $this->site_id = ! empty( $site_id ) ? $site_id : null;
    }

    /**
     * Make a request to the backend Google Calendar API.
     *
     * @param string     $method HTTP method.
     * @param string     $path   Endpoint path (after /google/).
     * @param array|null $body   Request body.
     * @param int        $timeout Timeout in seconds.
     * @return array|WP_Error Response data or error.
     */
    private function backend_request( string $method, string $path, ?array $body = null, int $timeout = 15 ) {
        if ( ! $this->site_id ) {
            $site_id = $this->backend->ensure_site_id();
            if ( is_wp_error( $site_id ) ) {
                return $site_id;
            }
            $this->site_id = $site_id;
        }

        $base = $this->backend->get_base_url();
        if ( empty( $base ) ) {
            return new WP_Error( 'boostbot_backend_not_configured', 'Backend not configured.' );
        }

        $url = $base . '/api/v1/sites/' . rawurlencode( $this->site_id ) . '/google/' . $path;

        $headers = array(
            'Accept'       => 'application/json',
            'Content-Type' => 'application/json',
        );

        $site_key = (string) BoostBot_Settings::get( 'backend_site_api_key', '' );
        if ( ! empty( $site_key ) ) {
            $headers['Authorization'] = 'Bearer ' . trim( $site_key );
        }

        $args = array(
            'method'  => $method,
            'timeout' => max( 5, min( 60, $timeout ) ),
            'headers' => $headers,
        );

        if ( null !== $body ) {
            $args['body'] = wp_json_encode( $body );
        }

        $response = wp_remote_request( $url, $args );

        if ( is_wp_error( $response ) ) {
            return $response;
        }

        $status = (int) wp_remote_retrieve_response_code( $response );
        $text   = (string) wp_remote_retrieve_body( $response );
        $json   = json_decode( $text, true );

        if ( ! is_array( $json ) ) {
            return new WP_Error( 'bad_response', 'Invalid response from backend.' );
        }

        if ( isset( $json['success'] ) && false === $json['success'] ) {
            $msg = $json['error']['message'] ?? 'Backend error';
            return new WP_Error( 'backend_error', $msg, array( 'http_status' => $status ) );
        }

        return $json['data'] ?? $json;
    }

    /**
     * Check if the backend has Google Calendar configured.
     *
     * @return bool
     */
    public function is_configured(): bool {
        $status = $this->get_cached_status();
        return ! empty( $status['configured'] );
    }

    /**
     * Always returns true — centralized backend manages credentials.
     *
     * @return bool
     */
    public function is_using_constants(): bool {
        return true;
    }

    /**
     * Check if connected to Google Calendar via backend.
     *
     * @return bool
     */
    public function is_connected(): bool {
        $status = $this->get_cached_status();
        return ! empty( $status['connected'] );
    }

    /**
     * Get authorization URL from backend.
     *
     * @param string $state Unused — state is managed by backend.
     * @return string Authorization URL.
     */
    public function get_auth_url( string $state = '' ): string {
        $return_url = admin_url( 'admin.php?page=boostbot#/integrations' );

        $result = $this->backend_request( 'GET', 'auth-url?' . http_build_query( array(
            'return_url' => $return_url,
        ) ) );

        if ( is_wp_error( $result ) ) {
            BoostBot_Logger::error( 'Failed to get Google auth URL from backend', array(
                'error' => $result->get_error_message(),
            ) );
            return '';
        }

        return $result['url'] ?? '';
    }

    /**
     * Handle OAuth callback.
     * Not used in proxied mode — backend handles the callback directly.
     *
     * @param string $code Authorization code.
     * @return bool
     */
    public function handle_callback( string $code ): bool {
        // In proxied mode, the backend handles the callback.
        // This method is kept for interface compatibility.
        return false;
    }

    /**
     * Get connected email.
     *
     * @return string|null Connected email or null.
     */
    public function get_connected_email(): ?string {
        $status = $this->get_cached_status();
        return $status['email'] ?? null;
    }

    /**
     * Create calendar event via backend.
     *
     * @param array $event_data Event data.
     * @return array|WP_Error Event result or error.
     */
    public function create_event( array $event_data ) {
        $attendees = array();
        if ( ! empty( $event_data['attendee_email'] ) ) {
            $attendees[] = $event_data['attendee_email'];
        }
        if ( ! empty( $event_data['attendees'] ) && is_array( $event_data['attendees'] ) ) {
            $attendees = array_merge( $attendees, $event_data['attendees'] );
        }

        // Deduplicate attendees
        $attendees = array_values( array_unique( array_filter( $attendees ) ) );

        BoostBot_Logger::info( '📅 Google Calendar create_event — sending to backend', array(
            'title'     => $event_data['title'] ?? '',
            'attendees' => $attendees,
            'start'     => $event_data['start_datetime'] ?? '',
            'end'       => $event_data['end_datetime'] ?? '',
        ) );

        $result = $this->backend_request( 'POST', 'create-event', array(
            'title'          => $event_data['title'] ?? __( 'פגישה', 'boostbot' ),
            'description'    => $event_data['description'] ?? '',
            'start_datetime' => $event_data['start_datetime'],
            'end_datetime'   => $event_data['end_datetime'],
            'timezone'       => $event_data['timezone'] ?? wp_timezone_string(),
            'attendees'      => $attendees,
            'location'       => $event_data['location'] ?? '',
            'add_meet_link'  => false,
        ) );

        if ( is_wp_error( $result ) ) {
            BoostBot_Logger::error( '📅 Google Calendar create_event failed (WP_Error)', array(
                'error' => $result->get_error_message(),
            ) );
            return $result;
        }

        if ( ! empty( $result['success'] ) ) {
            BoostBot_Logger::info( '📅 Google Calendar event created successfully', array(
                'event_id'        => $result['event_id'] ?? '',
                'attendees_count' => count( $attendees ),
            ) );
            return array(
                'success'   => true,
                'event_id'  => $result['event_id'] ?? '',
                'html_link' => $result['html_link'] ?? '',
            );
        }

        BoostBot_Logger::error( '📅 Google Calendar create_event — unexpected result', array(
            'result' => $result,
        ) );
        return new WP_Error( 'create_failed', $result['error'] ?? __( 'Failed to create event', 'boostbot' ) );
    }

    /**
     * Create meeting with Google Meet link via backend.
     *
     * @param array $data Meeting data.
     * @return array Meeting result.
     */
    public function create_meeting( array $data ): array {
        $result = $this->backend_request( 'POST', 'create-event', array(
            'title'          => $data['title'] ?? __( 'פגישה', 'boostbot' ),
            'description'    => $data['description'] ?? '',
            'start_datetime' => $data['start_datetime'],
            'end_datetime'   => $data['end_datetime'],
            'timezone'       => $data['timezone'] ?? 'Asia/Jerusalem',
            'attendees'      => $data['attendees'] ?? array(),
            'location'       => $data['location'] ?? '',
            'add_meet_link'  => true,
        ) );

        if ( is_wp_error( $result ) ) {
            return array(
                'success' => false,
                'error'   => $result->get_error_message(),
            );
        }

        if ( ! empty( $result['success'] ) ) {
            BoostBot_Logger::info( 'Google Meet created via backend', array(
                'event_id'  => $result['event_id'] ?? '',
                'meet_link' => $result['meet_link'] ?? '',
            ) );
            return array(
                'success'   => true,
                'event_id'  => $result['event_id'] ?? '',
                'html_link' => $result['html_link'] ?? '',
                'meet_link' => $result['meet_link'] ?? '',
            );
        }

        return array(
            'success' => false,
            'error'   => $result['error'] ?? __( 'Unknown error', 'boostbot' ),
        );
    }

    /**
     * Cancel calendar event via backend.
     *
     * @param string $event_id Google event ID.
     * @return bool True on success.
     */
    public function cancel_event( string $event_id ): bool {
        $result = $this->backend_request( 'POST', 'cancel-event', array(
            'event_id' => $event_id,
        ) );

        return ! is_wp_error( $result );
    }

    /**
     * Get free/busy periods via backend.
     *
     * @since 1.9.0
     * @param string $start_datetime ISO 8601 datetime.
     * @param string $end_datetime   ISO 8601 datetime.
     * @return array Busy periods.
     */
    public function get_freebusy( string $start_datetime, string $end_datetime ): array {
        $result = $this->backend_request( 'POST', 'freebusy', array(
            'start_datetime' => $start_datetime,
            'end_datetime'   => $end_datetime,
        ) );

        if ( is_wp_error( $result ) ) {
            BoostBot_Logger::error( 'Backend FreeBusy query failed', array(
                'error' => $result->get_error_message(),
            ) );
            return array();
        }

        return $result['busy'] ?? array();
    }

    /**
     * Create event from booking data.
     *
     * @param array $booking Booking data (name, phone, date, time, duration, type).
     * @return array|WP_Error Event result or error.
     */
    public function create_event_from_booking( array $booking ) {
        $type_label = ( $booking['type'] ?? 'call' ) === 'call'
            ? __( 'שיחה טלפונית', 'boostbot' )
            : __( 'פגישה', 'boostbot' );

        $title = sprintf( '%s - %s', $type_label, $booking['name'] );

        $description = sprintf(
            "%s: %s\n%s: %s\n%s: BoostBot",
            __( 'שם', 'boostbot' ),
            $booking['name'],
            __( 'טלפון', 'boostbot' ),
            $booking['phone'],
            __( 'מקור', 'boostbot' )
        );

        if ( ! empty( $booking['conversation_id'] ) ) {
            $description .= sprintf( "\n%s: %s", __( 'שיחה', 'boostbot' ), $booking['conversation_id'] );
        }

        $duration        = intval( $booking['duration'] ?? 30 );
        $start_datetime  = $booking['date'] . 'T' . $booking['time'] . ':00';
        $end_timestamp   = strtotime( $start_datetime ) + ( $duration * 60 );
        $end_datetime    = gmdate( 'Y-m-d\TH:i:s', $end_timestamp );

        return $this->create_event( array(
            'title'          => $title,
            'description'    => $description,
            'start_datetime' => $start_datetime,
            'end_datetime'   => $end_datetime,
        ) );
    }

    /**
     * Disconnect Google Calendar via backend.
     *
     * @return bool True on success.
     */
    public function disconnect(): bool {
        $result = $this->backend_request( 'POST', 'disconnect' );
        // Clear local cache
        delete_transient( self::STATUS_CACHE_OPTION );
        return ! is_wp_error( $result );
    }

    /**
     * Get connection status from backend.
     *
     * @return array Status array.
     */
    public function get_status(): array {
        $result = $this->backend_request( 'GET', 'status' );

        if ( is_wp_error( $result ) ) {
            return array(
                'configured' => false,
                'connected'  => false,
            );
        }

        // Cache the status locally for quick checks (short TTL so it self-heals).
        set_transient( self::STATUS_CACHE_OPTION, $result, 10 * MINUTE_IN_SECONDS );

        return $result;
    }

    /**
     * Save settings (calendar_id) via backend.
     *
     * @param array $settings Settings array.
     * @return bool True on success.
     */
    public function save_settings( array $settings ): bool {
        $result = $this->backend_request( 'PUT', 'settings', array(
            'calendar_id' => $settings['calendar_id'] ?? 'primary',
        ) );
        return ! is_wp_error( $result );
    }

    /**
     * Get cached status (avoid hitting backend on every check).
     * Falls back to live call if no cache.
     *
     * @return array Status data.
     */
    private function get_cached_status(): array {
        // Short-TTL transient so a revoked/expired Google connection self-heals instead of
        // trusting an unbounded cache. get_transient() returns false once it expires.
        $cached = get_transient( self::STATUS_CACHE_OPTION );

        if ( is_array( $cached ) ) {
            return $cached;
        }

        return $this->get_status();
    }
}
