<?php
namespace App\Services;

use App\Repositories\ConfigRepository;
use App\Utils\Logger;

// Ensure constants are loaded
if (!defined('DIDAR_API_BASE')) {
    require_once __DIR__ . '/../config/constants.php';
}

/**
 * Didar API Service
 * Handles all Didar API calls
 */
class DidarApiService
{
    private $configRepo;
    private $maxRetries = 3;
    private $retryDelay = 2; // seconds
    private $apiEnabled = false;

    public function __construct(ConfigRepository $configRepo)
    {
        $this->configRepo = $configRepo;
        $this->apiEnabled = $this->resolveApiEnabled();
    }

    public function isEnabled(): bool
    {
        return $this->apiEnabled;
    }

    private function resolveApiEnabled(): bool
    {
        $env = getenv('DIDAR_API_ENABLED');
        if ($env !== false && $env !== '') {
            return in_array(strtolower(trim((string)$env)), ['1', 'true', 'yes', 'on'], true);
        }

        try {
            $cfg = $this->configRepo->getValue('didar_api_enabled', '0');
            return in_array(strtolower(trim((string)$cfg)), ['1', 'true', 'yes', 'on'], true);
        } catch (\Throwable $e) {
            return false;
        }
    }

    /**
     * Get users from Didar API and cache them
     * This ensures we have the correct Didar UserId for each user
     */
    public function syncDidarUsers($apiKey = null)
    {
        if (!$this->apiEnabled) {
            Logger::logInfo("Didar API disabled - syncDidarUsers skipped");
            return false;
        }

        if ($apiKey === null) {
            $apiKey = $this->configRepo->getValue('api_key');
        }
        
        if (!$apiKey) {
            Logger::logError("API Key not set for syncing users", null, []);
            return false;
        }
        
        Logger::logInfo("Syncing users from Didar API");
        
        // Call the Didar User/List endpoint
        $result = $this->call('/User/List', 'POST', [], $apiKey);
        
        if (isset($result['error'])) {
            Logger::logError("Failed to fetch users from Didar", null, ['error' => $result['error']]);
            return false;
        }
        
        if (!isset($result['Response']) || !is_array($result['Response'])) {
            Logger::logError("Invalid response from Didar User/List", null, ['response' => $result]);
            return false;
        }
        
        Logger::logInfo("Synced users from Didar", ['count' => count($result['Response'])]);
        return $result['Response'];
    }

    public function call($endpoint, $method = 'POST', $data = [], $apiKey = null, $retryCount = 0)
    {
        if (!$this->apiEnabled) {
            Logger::logInfo("Didar API call blocked (disabled)", [
                'endpoint' => $endpoint,
                'method' => $method
            ]);
            return [
                'error' => 'Didar API is disabled',
                'disabled' => true,
                'http_code' => 0
            ];
        }

        // If API key not provided, get from database
        if ($apiKey === null) {
            $apiKey = $this->configRepo->getValue('api_key');
        }
        
        if (!$apiKey) {
            Logger::logError("API Key not set", null, ['endpoint' => $endpoint]);
            return ['error' => 'API Key not set'];
        }

        $url = DIDAR_API_BASE . $endpoint . "?apikey=" . urlencode($apiKey);
        
        Logger::logDebug("Calling Didar API", [
            'endpoint' => $endpoint,
            'method' => $method,
            'url' => str_replace($apiKey, '***', $url),
            'retry' => $retryCount
        ]);
        
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
        
        // Dynamic timeout: longer for deal/search to prevent timeouts
        $timeout = 60;
        $connectTimeout = 30;
        if (stripos($endpoint, '/deal/search') !== false) {
            $timeout = 120; // 2 minutes for deal/search
            $connectTimeout = 60;
        }
        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connectTimeout);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_MAXREDIRS, 5);
        
        // Rate Limit Protection
        usleep(200000);
        
        $headers = [];
        if (!empty($data)) {
            $postData = json_encode($data, JSON_UNESCAPED_UNICODE);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
            $headers[] = 'Content-Type: application/json';
        } else {
            // For POST requests without data, send empty JSON object
            if ($method === 'POST') {
                curl_setopt($ch, CURLOPT_POSTFIELDS, '{}');
                $headers[] = 'Content-Type: application/json';
            }
        }
        
        if (!empty($headers)) {
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        }
        
        $startTime = microtime(true);
        $response = curl_exec($ch);
        $endTime = microtime(true);
        $duration = round(($endTime - $startTime) * 1000, 2); // milliseconds
        
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        $curlErrno = curl_errno($ch);
        curl_close($ch);
        
        // Log request details
        Logger::logDebug("Didar API Response", [
            'endpoint' => $endpoint,
            'http_code' => $httpCode,
            'duration_ms' => $duration,
            'response_size' => strlen($response),
            'curl_error' => $error ?: null,
            'curl_errno' => $curlErrno ?: null
        ]);
        
        // Handle CURL errors with retry
        if ($error) {
            $errorMsg = 'CURL Error: ' . $error . ' (Code: ' . $curlErrno . ')';
            
            // Retry on connection errors
            if ($retryCount < $this->maxRetries && in_array($curlErrno, [CURLE_COULDNT_CONNECT, CURLE_OPERATION_TIMEOUTED, CURLE_HTTP_POST_ERROR])) {
                Logger::logWarning("Retrying API call", [
                    'endpoint' => $endpoint,
                    'attempt' => $retryCount + 1,
                    'max_retries' => $this->maxRetries,
                    'error' => $errorMsg,
                    'curl_errno' => $curlErrno
                ]);
                sleep($this->retryDelay);
                return $this->call($endpoint, $method, $data, $apiKey, $retryCount + 1);
            }
            
            Logger::logError("CURL Error in Didar API", null, [
                'endpoint' => $endpoint,
                'error' => $errorMsg,
                'http_code' => $httpCode,
                'curl_errno' => $curlErrno
            ]);
            
            return ['error' => $errorMsg, 'http_code' => $httpCode, 'curl_errno' => $curlErrno];
        }
        
        // Check if response is empty
        if (empty($response) || trim($response) === '') {
            $errorMsg = 'Empty response from Didar API';
            Logger::logError("Empty response from Didar API", null, [
                'endpoint' => $endpoint,
                'http_code' => $httpCode
            ]);
            return ['error' => $errorMsg, 'http_code' => $httpCode, 'raw_response' => ''];
        }
        
        $trimmed = ltrim($response);
        $isJsonLike = $trimmed !== '' && ($trimmed[0] === '{' || $trimmed[0] === '[');

        // Handle non-JSON responses explicitly (e.g., HTML error pages)
        if (!$isJsonLike) {
            $errorMsg = 'Non-JSON response from Didar API';
            Logger::logError("Non-JSON response from Didar API", null, [
                'endpoint' => $endpoint,
                'http_code' => $httpCode,
                'response_length' => strlen($response),
                'response_preview' => substr($response, 0, 500)
            ]);
            return [
                'error' => $errorMsg . ': HTTP ' . $httpCode,
                'http_code' => $httpCode,
                'raw_response' => substr($response, 0, 1000)
            ];
        }

        $json = json_decode($response, true);
        
        // Handle JSON decode errors
        if (json_last_error() !== JSON_ERROR_NONE) {
            $errorMsg = 'JSON Decode Error: ' . json_last_error_msg();
            Logger::logError("JSON decode error", null, [
                'endpoint' => $endpoint,
                'http_code' => $httpCode,
                'response_length' => strlen($response),
                'response_preview' => substr($response, 0, 500)
            ]);
            return ['error' => $errorMsg, 'http_code' => $httpCode, 'raw_response' => substr($response, 0, 1000)];
        }
        
        // Handle HTTP errors
        if ($httpCode !== 200) {
            $errorMsg = 'Didar API Error: HTTP ' . $httpCode;
            if (isset($json['Message'])) {
                $errorMsg .= ' - ' . $json['Message'];
            } elseif (isset($json['message'])) {
                $errorMsg .= ' - ' . $json['message'];
            } elseif (is_string($json)) {
                $errorMsg .= ' - ' . $json;
            }
            
            Logger::logError("Didar API HTTP Error", null, [
                'endpoint' => $endpoint,
                'http_code' => $httpCode,
                'response' => $json
            ]);
            
            return ['error' => $errorMsg, 'http_code' => $httpCode, 'response' => $json];
        }
        
        // Check if response has error structure
        if (isset($json['error']) || (isset($json['Status']) && $json['Status'] !== 'success')) {
            $errorMsg = isset($json['Message']) ? $json['Message'] : (isset($json['error']) ? $json['error'] : 'Unknown error');
            Logger::logError("Didar API returned error", null, [
                'endpoint' => $endpoint,
                'error' => $errorMsg,
                'response' => $json
            ]);
            return ['error' => $errorMsg, 'response' => $json];
        }
        
        Logger::logInfo("Didar API call successful", [
            'endpoint' => $endpoint,
            'duration_ms' => $duration
        ]);
        
        return $json;
    }

    /**
     * Search contact by phone in Didar.
     * Returns array of contacts (may be empty).
     */
    public function searchContactByPhone(string $phone): array
    {
        $phone = preg_replace('/\D/', '', $phone);
        if ($phone === '') {
            return [];
        }

        $payload = [
            'Criteria' => [
                'MobilePhone' => $phone
            ],
            'From' => 0,
            'Limit' => 5
        ];

        $res = $this->call('/contact/search', 'POST', $payload);
        if (isset($res['error'])) {
            Logger::logWarning('Didar searchContactByPhone failed', ['phone' => $phone, 'error' => $res['error']]);
            return [];
        }

        // Responses may be under Response.List or Response
        if (isset($res['Response']['List']) && is_array($res['Response']['List'])) {
            return $res['Response']['List'];
        }
        if (isset($res['Response']) && is_array($res['Response'])) {
            return $res['Response'];
        }
        return [];
    }

    /**
     * Search multiple phones and capture errors.
     * Returns ['contacts'=>[], 'errors'=>[]]
     */
    public function searchContactsByPhonesDetailed(array $phones, string $field = 'MobilePhone'): array
    {
        $all = [];
        $seenIds = [];
        $errors = [];
        foreach ($phones as $p) {
            $res = $this->call('/contact/search', 'POST', [
                'Criteria' => [$field => preg_replace('/\D/', '', $p)],
                'From' => 0,
                'Limit' => 5
            ]);
            if (isset($res['error'])) {
                $errors[] = $res['error'];
                continue;
            }
            $list = [];
            if (isset($res['Response']['List']) && is_array($res['Response']['List'])) {
                $list = $res['Response']['List'];
            } elseif (isset($res['Response']) && is_array($res['Response'])) {
                $list = $res['Response'];
            }
            foreach ($list as $c) {
                $id = $c['Id'] ?? ($c['ContactId'] ?? null);
                if ($id && isset($seenIds[$id])) {
                    continue;
                }
                if ($id) {
                    $seenIds[$id] = true;
                }
                $all[] = $c;
            }
        }
        return ['contacts' => $all, 'errors' => $errors];
    }

    /**
     * Search contacts by multiple phone variants; merges distinct results.
     */
    public function searchContactsByPhones(array $phones): array
    {
        $all = [];
        $seenIds = [];
        foreach ($phones as $p) {
            foreach ($this->searchContactByPhone($p) as $c) {
                $id = $c['Id'] ?? ($c['ContactId'] ?? null);
                if ($id && isset($seenIds[$id])) {
                    continue;
                }
                if ($id) {
                    $seenIds[$id] = true;
                }
                $all[] = $c;
            }
        }
        return $all;
    }
}

