<?php

namespace Core\App\Controllers;

use Core\App\Models\Settings;

/**
 * Google Sheets OAuth2 Controller
 * يتعامل مع:
 * 1. عرض صفحة إعداد Google Sheets
 * 2. بدء OAuth2 flow
 * 3. استقبال callback من Google
 * 4. حفظ إعدادات الـ sheet
 * 5. قطع الاتصال
 * 6. API: جلب الملفات والـ sheets
 */
class GoogleSheetsOAuthController
{
    private Settings $settings;

    // Google OAuth2 endpoints
    private const AUTH_URL  = 'https://accounts.google.com/o/oauth2/v2/auth';
    private const TOKEN_URL = 'https://oauth2.googleapis.com/token';
    private const SCOPE     = 'https://www.googleapis.com/auth/spreadsheets https://www.googleapis.com/auth/drive.readonly';

    public function __construct()
    {
        $this->settings = new Settings();
    }

    /* =====================================================
       صفحة الإعداد الرئيسية
    ===================================================== */
    public function index()
    {
        $clientId      = $this->settings->get('gsheets_oauth_client_id', '');
        $clientSecret  = $this->settings->get('gsheets_oauth_client_secret', '');
        $accessToken   = $this->settings->get('gsheets_oauth_access_token', '');
        $refreshToken  = $this->settings->get('gsheets_oauth_refresh_token', '');
        $spreadsheetId = $this->settings->get('gsheets_oauth_spreadsheet_id', '');
        $sheetName     = $this->settings->get('gsheets_oauth_sheet_name', 'Orders');
        $startRow      = $this->settings->get('gsheets_oauth_start_row', '2');
        $mergeVariants = $this->settings->get('gsheets_oauth_merge_variants', '0');
        $isEnabled     = $this->settings->get('gsheets_oauth_enabled', '0');
        $tokenExpiry   = (int)$this->settings->get('gsheets_oauth_token_expiry', '0');
        $connectedEmail= $this->settings->get('gsheets_oauth_connected_email', '');

        $isConnected = !empty($refreshToken) || (!empty($accessToken) && $tokenExpiry > time());
        $isConfigured = $isConnected && !empty($spreadsheetId);

        require ROOT_PATH . '/admin/templates/header.php';
        require ROOT_PATH . '/admin/templates/settings/gsheets_oauth.php';
        require ROOT_PATH . '/admin/templates/footer.php';
    }

    /* =====================================================
       حفظ Client ID و Secret
    ===================================================== */
    public function saveCredentials()
    {
        $clientId     = trim($_POST['client_id']     ?? '');
        $clientSecret = trim($_POST['client_secret'] ?? '');

        if (empty($clientId) || empty($clientSecret)) {
            $_SESSION['flash_error'] = __('gsheets.error_credentials', 'Client ID and Secret are required');
            header('Location: /admin/settings/gsheets');
            exit;
        }

        $this->settings->set('gsheets_oauth_client_id',     $clientId);
        $this->settings->set('gsheets_oauth_client_secret', $clientSecret);

        $_SESSION['flash_success'] = __('gsheets.credentials_saved', 'Credentials saved. Now connect your Google account.');
        header('Location: /admin/settings/gsheets');
        exit;
    }

    /* =====================================================
       حفظ إعدادات الـ Sheet
    ===================================================== */
    public function saveSheetConfig()
    {
        $spreadsheetId = trim($_POST['spreadsheet_id'] ?? '');
        $sheetName     = trim($_POST['sheet_name']     ?? 'Orders');
        $startRow      = max(1, (int)($_POST['start_row'] ?? 2));
        $mergeVariants = isset($_POST['merge_variants']) ? '1' : '0';
        $isEnabled     = isset($_POST['enabled'])       ? '1' : '0';
        $exportMode    = in_array($_POST['export_mode'] ?? '', ['all_orders', 'confirmed_only'], true)
                         ? $_POST['export_mode']
                         : 'confirmed_only';

        $this->settings->set('gsheets_oauth_spreadsheet_id', $spreadsheetId);
        $this->settings->set('gsheets_oauth_sheet_name',     $sheetName);
        $this->settings->set('gsheets_oauth_start_row',      $startRow);
        $this->settings->set('gsheets_oauth_merge_variants', $mergeVariants);
        $this->settings->set('gsheets_oauth_enabled',        $isEnabled);
        $this->settings->set('gsheets_export_mode',          $exportMode);

        $_SESSION['flash_success'] = __('gsheets.config_saved', 'Sheet configuration saved successfully');
        header('Location: /admin/settings/gsheets');
        exit;
    }

    /* =====================================================
       بدء OAuth2 — إعادة توجيه لـ Google
    ===================================================== */
    public function connect()
    {
        $clientId = $this->settings->get('gsheets_oauth_client_id', '');
        if (empty($clientId)) {
            $_SESSION['flash_error'] = __('gsheets.error_no_client_id', 'Please enter Client ID first');
            header('Location: /admin/settings/gsheets');
            exit;
        }

        // حماية CSRF بـ state
        $state = bin2hex(random_bytes(16));
        $_SESSION['gsheets_oauth_state'] = $state;

        $redirectUri = $this->getRedirectUri();

        $params = http_build_query([
            'client_id'     => $clientId,
            'redirect_uri'  => $redirectUri,
            'response_type' => 'code',
            'scope'         => self::SCOPE,
            'access_type'   => 'offline',  // نحصل على refresh_token
            'prompt'        => 'consent',  // مهم: يضمن الحصول على refresh_token دائماً
            'state'         => $state,
        ]);

        header('Location: ' . self::AUTH_URL . '?' . $params);
        exit;
    }

    /* =====================================================
       استقبال Callback من Google
    ===================================================== */
    public function callback()
    {
        $code  = $_GET['code']  ?? '';
        $state = $_GET['state'] ?? '';
        $error = $_GET['error'] ?? '';

        // رفض Google
        if (!empty($error)) {
            $_SESSION['flash_error'] = __('gsheets.auth_denied', 'Google authorization was denied');
            header('Location: /admin/settings/gsheets');
            exit;
        }

        // التحقق من CSRF state
        $savedState = $_SESSION['gsheets_oauth_state'] ?? '';
        if (empty($savedState) || $state !== $savedState) {
            $_SESSION['flash_error'] = __('gsheets.invalid_state', 'Invalid OAuth state. Please try again.');
            header('Location: /admin/settings/gsheets');
            exit;
        }
        unset($_SESSION['gsheets_oauth_state']);

        if (empty($code)) {
            $_SESSION['flash_error'] = __('gsheets.no_code', 'No authorization code received');
            header('Location: /admin/settings/gsheets');
            exit;
        }

        // استبدال code بـ tokens
        try {
            $tokens = $this->exchangeCode($code);

            $this->settings->set('gsheets_oauth_access_token',  $tokens['access_token']);
            $this->settings->set('gsheets_oauth_token_expiry',  time() + (int)($tokens['expires_in'] ?? 3600));

            if (!empty($tokens['refresh_token'])) {
                $this->settings->set('gsheets_oauth_refresh_token', $tokens['refresh_token']);
            }

            // جلب email الحساب المرتبط
            try {
                $userInfo = $this->getUserInfo($tokens['access_token']);
                if (!empty($userInfo['email'])) {
                    $this->settings->set('gsheets_oauth_connected_email', $userInfo['email']);
                }
            } catch (\Throwable $e) {}

            $_SESSION['flash_success'] = __('gsheets.connected', 'Google account connected successfully!');

        } catch (\Throwable $e) {
            $_SESSION['flash_error'] = __('gsheets.token_error', 'Failed to get token: ') . $e->getMessage();
        }

        header('Location: /admin/settings/gsheets');
        exit;
    }

    /* =====================================================
       قطع الاتصال
    ===================================================== */
    public function disconnect()
    {
        \Core\System\Csrf::check();
        // حذف كل tokens
        $keysToDelete = [
            'gsheets_oauth_access_token',
            'gsheets_oauth_refresh_token',
            'gsheets_oauth_token_expiry',
            'gsheets_oauth_connected_email',
        ];

        foreach ($keysToDelete as $key) {
            $this->settings->set($key, '');
        }

        $_SESSION['flash_success'] = __('gsheets.disconnected', 'Google account disconnected');
        header('Location: /admin/settings/gsheets');
        exit;
    }

    /* =====================================================
       AJAX — جلب ملفات Google Sheets
    ===================================================== */
    public function listFiles()
    {
        header('Content-Type: application/json');

        try {
            $token = $this->getValidAccessToken();

            $url = 'https://www.googleapis.com/drive/v3/files?'
                . http_build_query([
                    'q'        => "mimeType='application/vnd.google-apps.spreadsheet' and trashed=false",
                    'fields'   => 'files(id,name)',
                    'orderBy'  => 'modifiedTime desc',
                    'pageSize' => 50,
                ]);

            $result = $this->httpGet($url, $token);
            $files  = $result['files'] ?? [];

            echo json_encode(['success' => true, 'files' => $files]);

        } catch (\Throwable $e) {
            echo json_encode(['success' => false, 'error' => $e->getMessage()]);
        }
        exit;
    }

    /* =====================================================
       AJAX — جلب sheets داخل ملف معين
    ===================================================== */
    public function listSheets()
    {
        header('Content-Type: application/json');

        $spreadsheetId = trim($_GET['spreadsheet_id'] ?? '');
        if (empty($spreadsheetId)) {
            echo json_encode(['success' => false, 'error' => 'spreadsheet_id required']);
            exit;
        }

        try {
            $token = $this->getValidAccessToken();

            $url    = 'https://sheets.googleapis.com/v4/spreadsheets/' . rawurlencode($spreadsheetId)
                    . '?fields=sheets(properties(sheetId,title))';
            $result = $this->httpGet($url, $token);

            $sheets = array_map(
                fn($s) => $s['properties']['title'] ?? '',
                $result['sheets'] ?? []
            );

            echo json_encode(['success' => true, 'sheets' => $sheets]);

        } catch (\Throwable $e) {
            echo json_encode(['success' => false, 'error' => $e->getMessage()]);
        }
        exit;
    }

    /* =====================================================
       جلب Access Token صالح (refresh إذا انتهت صلاحيته)
    ===================================================== */
    public function getValidAccessToken(): string
    {
        $accessToken  = $this->settings->get('gsheets_oauth_access_token', '');
        $refreshToken = $this->settings->get('gsheets_oauth_refresh_token', '');
        $tokenExpiry  = (int)$this->settings->get('gsheets_oauth_token_expiry', '0');

        // إذا كان صالحاً (مع هامش 60 ثانية)
        if (!empty($accessToken) && $tokenExpiry > (time() + 60)) {
            return $accessToken;
        }

        // تجديد باستخدام refresh_token
        if (empty($refreshToken)) {
            throw new \RuntimeException('not_connected');
        }

        $clientId     = $this->settings->get('gsheets_oauth_client_id', '');
        $clientSecret = $this->settings->get('gsheets_oauth_client_secret', '');

        $ch = curl_init(self::TOKEN_URL);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST           => true,
            CURLOPT_POSTFIELDS     => http_build_query([
                'client_id'     => $clientId,
                'client_secret' => $clientSecret,
                'refresh_token' => $refreshToken,
                'grant_type'    => 'refresh_token',
            ]),
            CURLOPT_HTTPHEADER     => ['Content-Type: application/x-www-form-urlencoded'],
            CURLOPT_CONNECTTIMEOUT => 5,
            CURLOPT_TIMEOUT        => 10,
        ]);

        $res  = curl_exec($ch);
        $code = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($code < 200 || $code >= 300) {
            throw new \RuntimeException('token_refresh_failed_http_' . $code);
        }

        $data = json_decode($res, true);
        if (empty($data['access_token'])) {
            throw new \RuntimeException('token_refresh_invalid_response');
        }

        $newToken  = $data['access_token'];
        $newExpiry = time() + (int)($data['expires_in'] ?? 3600);

        $this->settings->set('gsheets_oauth_access_token', $newToken);
        $this->settings->set('gsheets_oauth_token_expiry', $newExpiry);

        return $newToken;
    }

    /* =====================================================
       إضافة صف إلى الـ Sheet (يُستدعى من GoogleSheetsExporter)
    ===================================================== */
    public function appendRow(array $values): void
    {
        $spreadsheetId = $this->settings->get('gsheets_oauth_spreadsheet_id', '');
        $sheetName     = $this->settings->get('gsheets_oauth_sheet_name', 'Orders');

        if (empty($spreadsheetId)) {
            throw new \RuntimeException('gsheets_not_configured');
        }

        $token = $this->getValidAccessToken();

        $range = rawurlencode($sheetName . '!A1');
        $url   = 'https://sheets.googleapis.com/v4/spreadsheets/'
               . rawurlencode($spreadsheetId)
               . '/values/' . $range
               . ':append?valueInputOption=USER_ENTERED&insertDataOption=INSERT_ROWS';

        $body = json_encode(['values' => [$values]], JSON_UNESCAPED_UNICODE);

        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST           => true,
            CURLOPT_POSTFIELDS     => $body,
            CURLOPT_HTTPHEADER     => [
                'Authorization: Bearer ' . $token,
                'Content-Type: application/json',
            ],
            CURLOPT_CONNECTTIMEOUT => 4,
            CURLOPT_TIMEOUT        => 10,
        ]);

        $res  = curl_exec($ch);
        $code = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($code < 200 || $code >= 300) {
            throw new \RuntimeException('sheets_append_failed_http_' . $code . ': ' . $res);
        }
    }

    /* =====================================================
       HELPERS
    ===================================================== */
    private function exchangeCode(string $code): array
    {
        $clientId     = $this->settings->get('gsheets_oauth_client_id', '');
        $clientSecret = $this->settings->get('gsheets_oauth_client_secret', '');
        $redirectUri  = $this->getRedirectUri();

        $ch = curl_init(self::TOKEN_URL);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST           => true,
            CURLOPT_POSTFIELDS     => http_build_query([
                'code'          => $code,
                'client_id'     => $clientId,
                'client_secret' => $clientSecret,
                'redirect_uri'  => $redirectUri,
                'grant_type'    => 'authorization_code',
            ]),
            CURLOPT_HTTPHEADER     => ['Content-Type: application/x-www-form-urlencoded'],
            CURLOPT_CONNECTTIMEOUT => 5,
            CURLOPT_TIMEOUT        => 15,
        ]);

        $res  = curl_exec($ch);
        $code_h = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $err  = curl_error($ch);
        curl_close($ch);

        if ($res === false) {
            throw new \RuntimeException('curl_error: ' . $err);
        }

        $data = json_decode($res, true);

        if ($code_h < 200 || $code_h >= 300 || empty($data['access_token'])) {
            throw new \RuntimeException($data['error_description'] ?? $data['error'] ?? 'token_exchange_failed');
        }

        return $data;
    }

    private function getUserInfo(string $accessToken): array
    {
        $result = $this->httpGet('https://www.googleapis.com/oauth2/v2/userinfo', $accessToken);
        return $result;
    }

    private function httpGet(string $url, string $token): array
    {
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $token],
            CURLOPT_CONNECTTIMEOUT => 5,
            CURLOPT_TIMEOUT        => 10,
        ]);

        $res  = curl_exec($ch);
        $code = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($code < 200 || $code >= 300) {
            throw new \RuntimeException('http_' . $code);
        }

        return json_decode($res, true) ?: [];
    }

    private function getRedirectUri(): string
    {
        $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
        $host     = $_SERVER['HTTP_HOST'] ?? 'localhost';
        return $protocol . '://' . $host . '/admin/settings/gsheets/callback';
    }

    /* =====================================================
       Queue Monitor Page
    ===================================================== */
    public function monitor(): void
    {
        $spreadsheetId = $this->settings->get('gsheets_oauth_spreadsheet_id', '');
        $sheetName     = $this->settings->get('gsheets_oauth_sheet_name', 'Orders');

        require ROOT_PATH . '/admin/templates/header.php';
        require ROOT_PATH . '/admin/templates/settings/gsheets_monitor.php';
        require ROOT_PATH . '/admin/templates/footer.php';
    }

    /* =====================================================
       Retry a dead job — move it back to pending
    ===================================================== */
    public function retryJob(): void
    {
        $filename = basename(trim($_POST['filename'] ?? ''));
        $month    = basename(trim($_POST['month']    ?? ''));

        if (empty($filename) || !preg_match('/^\d{6}$/', $month)) {
            $_SESSION['flash_error'] = 'Invalid job reference.';
            header('Location: /admin/settings/gsheets/monitor');
            exit;
        }

        $deadPath    = ROOT_PATH . '/storage/queue/gsheets/dead/' . $month . '/' . $filename;
        $pendingPath = ROOT_PATH . '/storage/queue/gsheets/pending/' . $filename;

        if (!file_exists($deadPath)) {
            $_SESSION['flash_error'] = 'Job file not found.';
            header('Location: /admin/settings/gsheets/monitor');
            exit;
        }

        // نُعيد ضبط عداد المحاولات
        $job = json_decode((string)file_get_contents($deadPath), true) ?: [];
        $job['attempts']   = 0;
        $job['last_error'] = null;
        $job['retried_at'] = date('Y-m-d H:i:s');

        @file_put_contents($pendingPath, json_encode($job, JSON_UNESCAPED_UNICODE));
        @unlink($deadPath);

        $_SESSION['flash_success'] = __('gsheets.mon_retried', 'Job moved back to queue successfully.');
        header('Location: /admin/settings/gsheets/monitor');
        exit;
    }
}