<?php
namespace App\Services;

use App\Repositories\UserRepository;
use App\Repositories\PersonRepository;
use App\Repositories\DealRepository;
use App\Repositories\ActivityRepository;
use App\Repositories\ConfigRepository;
use App\Repositories\VirtualStageRepository;
use App\Services\DidarApiService;
use App\Services\VirtualStageService;
use App\Utils\Logger;
use App\Utils\PhoneNormalizer;
use PDO;
use PDOException;

/**
 * Sync Service
 * Handles synchronization with Didar API
 */
class SyncService
{
    private $didarApi;
    private $userRepo;
    private $personRepo;
    private $dealRepo;
    private $activityRepo;
    private $configRepo;
    private $virtualStageService;
    private $db;

    public function __construct(
        DidarApiService $didarApi,
        UserRepository $userRepo,
        PersonRepository $personRepo,
        DealRepository $dealRepo,
        ActivityRepository $activityRepo,
        ConfigRepository $configRepo,
        VirtualStageService $virtualStageService,
        $db
    ) {
        $this->didarApi = $didarApi;
        $this->userRepo = $userRepo;
        $this->personRepo = $personRepo;
        $this->dealRepo = $dealRepo;
        $this->activityRepo = $activityRepo;
        $this->configRepo = $configRepo;
        $this->virtualStageService = $virtualStageService;
        $this->db = $db;
    }

    /**
     * Sync users from Didar
     */
    public function syncUsers($from = 0, $limit = 500)
    {
        $res = $this->didarApi->call('/User/List', 'POST');
        
        if (isset($res['error'])) {
            throw new \Exception("خطا در دریافت کاربران: " . $res['error']);
        }
        
        $users = $res['Response'] ?? [];
        $synced = 0;
        
        foreach ($users as $userData) {
            try {
                $user = new \App\Models\User([
                    'didar_user_id' => $userData['UserId'] ?? $userData['Id'] ?? '',
                    'email' => $userData['UserName'] ?? '',
                    'first_name' => $userData['FirstName'] ?? '',
                    'last_name' => $userData['LastName'] ?? '',
                    'display_name' => $userData['DisplayName'] ?? '',
                    'role' => 'agent',
                    'is_active' => 1,
                    'last_sync' => date('Y-m-d H:i:s')
                ]);
                
                $this->userRepo->save($user);
                $synced++;
                
                $this->logSync('user', $user->didar_user_id, 'fetch', 'success');
            } catch (Exception $e) {
                Logger::logError("Failed to sync user", $e, ['user_data' => $userData]);
                $this->logSync('user', $userData['UserId'] ?? '', 'fetch', 'failed', $e->getMessage());
            }
        }
        
        return ['synced' => $synced, 'total' => count($users)];
    }

    /**
     * Sync persons from Didar
     */
    public function syncPersons($from = 0, $limit = 500)
    {
        $searchCriteria = [
            'ContactType' => 0,
            'IsDeleted' => 0,
            'IsPinned' => -1,
            'IsVIP' => -1,
            'LeadType' => -1,
            'Pin' => -1,
            'SortOrder' => 1,
            'Keywords' => '',
            'SearchFromTime' => '1930-01-01T00:00:00.000Z',
            'SearchToTime' => '9999-12-01T00:00:00.000Z',
            'CustomFields' => [],
            'FilterId' => null
        ];
        
        $res = $this->didarApi->call('/contact/PersonSearch', 'POST', [
            'Criteria' => $searchCriteria,
            'From' => $from,
            'Limit' => $limit
        ]);
        
        if (isset($res['error'])) {
            throw new \Exception("خطا در دریافت اشخاص: " . $res['error']);
        }
        
        $persons = $res['Response'] ?? [];
        $synced = 0;
        
        foreach ($persons as $personData) {
            try {
                $person = new \App\Models\Person([
                    'didar_contact_id' => $personData['Id'] ?? '',
                    'owner_didar_id' => $personData['OwnerId'] ?? null,
                    'code' => $personData['Code'] ?? '',
                    'first_name' => $personData['FirstName'] ?? '',
                    'last_name' => $personData['LastName'] ?? '',
                    'mobile_phone' => PhoneNormalizer::normalize($personData['MobilePhone'] ?? ''),
                    'secondary_mobile_phone' => PhoneNormalizer::normalize($personData['Phone'] ?? ''),
                    'work_phone' => PhoneNormalizer::normalize($personData['WorkPhone'] ?? ''),
                    'email' => $personData['Email'] ?? '',
                    'contact_type' => 'Person',
                    'city' => $personData['City'] ?? '',
                    'job_title' => $personData['JobTitle'] ?? '',
                    'acquaintance_source' => $personData['AcquaintanceSource'] ?? '',
                    'acquaintance_detail' => $personData['AcquaintanceDetail'] ?? '',
                    'content_topic' => $personData['ContentTopic'] ?? '',
                    'national_id' => $personData['NationalId'] ?? '',
                    'has_previous_purchase' => array_key_exists('HasPreviousPurchase', $personData)
                        ? ($personData['HasPreviousPurchase'] ? 1 : 0)
                        : null,
                    'birth_date' => $personData['BirthDate'] ?? null,
                    'register_time' => $personData['RegisterTime'] ?? null,
                    'visibility_type' => $personData['VisibilityType'] ?? '',
                    'background_info' => $personData['BackgroundInfo'] ?? '',
                    // دیگر از دیدار برای محصولات همگام‌سازی نکنیم
                    'customer_products' => '',
                    'last_sync' => date('Y-m-d H:i:s'),
                    'raw_json' => json_encode($personData, JSON_UNESCAPED_UNICODE)
                ]);
                
                $this->personRepo->save($person);
                $synced++;
                
                // Update virtual stage
                $this->virtualStageService->update($person->didar_contact_id);
                
                $this->logSync('person', $person->didar_contact_id, 'fetch', 'success');
            } catch (Exception $e) {
                Logger::logError("Failed to sync person", $e, ['person_data' => $personData]);
                $this->logSync('person', $personData['Id'] ?? '', 'fetch', 'failed', $e->getMessage());
            }
        }
        
        return ['synced' => $synced, 'total' => count($persons), 'has_more' => count($persons) >= $limit];
    }

    /**
     * Sync deals from Didar
     */
    public function syncDeals($from = 0, $limit = 250)
    {
        $searchCriteria = [
            'IsDeleted' => 0,
            'SortOrder' => 1,
            'Keywords' => '',
            'SearchFromTime' => '1930-01-01T00:00:00.000Z',
            'SearchToTime' => '9999-12-01T00:00:00.000Z',
            'CustomFields' => [],
            'FilterId' => null
        ];
        
        $res = $this->didarApi->call('/deal/search', 'POST', [
            'Criteria' => $searchCriteria,
            'From' => $from,
            'Limit' => $limit
        ]);
        
        if (isset($res['error'])) {
            throw new \Exception("خطا در دریافت معاملات: " . $res['error']);
        }
        
        $deals = $res['Response'] ?? [];
        $synced = 0;
        
        foreach ($deals as $dealData) {
            try {
                $contactDidarId = $dealData['ContactId'] ?? null;
                $localPersonId = null;
                if ($contactDidarId) {
                    $person = $this->personRepo->findByDidarId($contactDidarId);
                    if ($person) {
                        $localPersonId = $person->id;
                    }
                }

                $deal = new \App\Models\Deal([
                    'didar_deal_id' => $dealData['Id'] ?? '',
                    'owner_didar_id' => $dealData['OwnerId'] ?? null,
                    'contact_didar_id' => $contactDidarId,
                    'local_person_id' => $localPersonId,
                    'title' => $dealData['Title'] ?? '',
                    'code' => $dealData['Code'] ?? '',
                    'status' => $dealData['Status'] ?? 'Pending',
                    'pipeline_stage_id' => $dealData['PipelineStageId'] ?? '',
                    'pipeline_stage_title' => $dealData['PipelineStageTitle'] ?? '',
                    'estimated_price' => $dealData['EstimatedPrice'] ?? 0,
                    'final_price' => $dealData['FinalPrice'] ?? 0,
                    'probability' => $dealData['Probability'] ?? 0,
                    'is_paid' => isset($dealData['IsPaid']) && $dealData['IsPaid'] ? 1 : 0,
                    'payment_short_link' => $dealData['PaymentShortLink'] ?? '',
                    'register_time' => $dealData['RegisterTime'] ?? null,
                    'last_update_time' => $dealData['LastUpdateTime'] ?? null,
                    'won_time' => $dealData['WonTime'] ?? null,
                    'lost_time' => $dealData['LostTime'] ?? null,
                    'visibility_type' => $dealData['VisibilityType'] ?? '',
                    'last_sync' => date('Y-m-d H:i:s'),
                    'raw_json' => json_encode($dealData, JSON_UNESCAPED_UNICODE)
                ]);
                
                $this->dealRepo->save($deal);
                $synced++;
                
                // Update virtual stage for contact
                if ($deal->contact_didar_id) {
                    $this->virtualStageService->update($deal->contact_didar_id);
                }
                
                $this->logSync('deal', $deal->didar_deal_id, 'fetch', 'success');
            } catch (Exception $e) {
                Logger::logError("Failed to sync deal", $e, ['deal_data' => $dealData]);
                $this->logSync('deal', $dealData['Id'] ?? '', 'fetch', 'failed', $e->getMessage());
            }
        }
        
        return ['synced' => $synced, 'total' => count($deals), 'has_more' => count($deals) >= $limit];
    }

    /**
     * Sync activities from Didar
     */
    public function syncActivities($from = 0, $limit = 500)
    {
        $searchCriteria = [
            'IsDeleted' => 0,
            'SortOrder' => 1,
            'Keywords' => '',
            'SearchFromTime' => '1930-01-01T00:00:00.000Z',
            'SearchToTime' => '9999-12-01T00:00:00.000Z',
            'CustomFields' => [],
            'FilterId' => null
        ];
        
        $res = $this->didarApi->call('/activity/search', 'POST', [
            'Criteria' => $searchCriteria,
            'From' => $from,
            'Limit' => $limit
        ]);
        
        if (isset($res['error'])) {
            throw new \Exception("خطا در دریافت فعالیت‌ها: " . $res['error']);
        }
        
        $activities = $res['Response'] ?? [];
        $synced = 0;
        
        foreach ($activities as $activityData) {
            try {
                $activity = new \App\Models\Activity([
                    'didar_activity_id' => $activityData['Id'] ?? '',
                    'activity_type_id' => $activityData['ActivityTypeId'] ?? '',
                    'activity_type_title' => $activityData['ActivityTypeTitle'] ?? '',
                    'owner_didar_id' => $activityData['OwnerId'] ?? null,
                    'deal_didar_id' => $activityData['DealId'] ?? null,
                    'contact_didar_id' => $activityData['ContactId'] ?? null,
                    'title' => $activityData['Title'] ?? '',
                    'note' => $activityData['Note'] ?? '',
                    'result_note' => $activityData['ResultNote'] ?? '',
                    'is_done' => isset($activityData['IsDone']) && $activityData['IsDone'] ? 1 : 0,
                    'due_date' => $activityData['DueDate'] ?? null,
                    'done_date' => $activityData['DoneDate'] ?? null,
                    'duration' => $activityData['Duration'] ?? 0,
                    'activity_category' => $activityData['ActivityCategory'] ?? '',
                    'direction' => $activityData['Direction'] ?? 'outgoing',
                    'stage' => $activityData['Stage'] ?? '',
                    'register_date' => $activityData['RegisterDate'] ?? null,
                    'last_update_time' => $activityData['LastUpdateTime'] ?? null,
                    'last_sync' => date('Y-m-d H:i:s'),
                    'raw_json' => json_encode($activityData, JSON_UNESCAPED_UNICODE)
                ]);
                
                $this->activityRepo->save($activity);
                $synced++;
                
                // Update virtual stage for contact
                if ($activity->contact_didar_id) {
                    $this->virtualStageService->update($activity->contact_didar_id);
                }
                
                $this->logSync('activity', $activity->didar_activity_id, 'fetch', 'success');
            } catch (Exception $e) {
                Logger::logError("Failed to sync activity", $e, ['activity_data' => $activityData]);
                $this->logSync('activity', $activityData['Id'] ?? '', 'fetch', 'failed', $e->getMessage());
            }
        }
        
        return ['synced' => $synced, 'total' => count($activities), 'has_more' => count($activities) >= $limit];
    }

    /**
     * Log sync operation
     */
    private function logSync($entityType, $entityId, $action, $status, $errorMsg = null, $httpCode = null, $responseData = null)
    {
        $pdo = $this->db->getPdo();
        $maxRetries = 5;
        $attempt = 0;
        
        while ($attempt < $maxRetries) {
            try {
                $stmt = $pdo->prepare("INSERT INTO sync_log (entity_type, entity_id, action, status, error_message, http_code, response_data) VALUES (?, ?, ?, ?, ?, ?, ?)");
                $responseJson = $responseData ? json_encode($responseData, JSON_UNESCAPED_UNICODE) : null;
                $stmt->execute([$entityType, $entityId, $action, $status, $errorMsg, $httpCode, $responseJson]);
                
                if ($status === 'failed') {
                    Logger::logError("Sync failed", null, [
                        'entity_type' => $entityType,
                        'entity_id' => $entityId,
                        'action' => $action,
                        'error' => $errorMsg,
                        'http_code' => $httpCode
                    ]);
                } else {
                    Logger::logInfo("Sync success", [
                        'entity_type' => $entityType,
                        'entity_id' => $entityId,
                        'action' => $action
                    ]);
                }
                return;
            } catch (PDOException $e) {
                $attempt++;
                if ($attempt >= $maxRetries) {
                    Logger::logError("Failed to write sync log after $maxRetries attempts", $e);
                    return;
                }
                usleep(100000 * $attempt);
            }
        }
    }
}

