<?php
namespace App\Controllers;

use App\Models\Person;
use App\Repositories\ConfigRepository;
use App\Repositories\PersonRepository;
use App\Repositories\ServiceGovernanceRepository;
use App\Utils\Logger;
use App\Utils\PhoneNormalizer;
use App\Utils\Sanitizer;

class IntegrationController extends ApiController
{
    private ConfigRepository $configRepo;
    private PersonRepository $personRepo;
    private ServiceGovernanceRepository $serviceGovernanceRepo;

    public function __construct(
        ConfigRepository $configRepo,
        PersonRepository $personRepo,
        ServiceGovernanceRepository $serviceGovernanceRepo
    ) {
        $this->configRepo = $configRepo;
        $this->personRepo = $personRepo;
        $this->serviceGovernanceRepo = $serviceGovernanceRepo;
    }

    public function getLeadAssignment(): void
    {
        try {
            $this->assertAuthorized('get_lead_assignment');
            $criteria = $this->extractLookupCriteria();
            $row = $this->findLeadForExternalLookup($criteria);

            if (!$row) {
                $this->successResponse($this->buildMissingLeadResponse());
            }

            $this->successResponse($this->buildLeadAssignmentPayload($row));
        } catch (\Throwable $e) {
            Logger::logError('External lead assignment lookup failed', $e, [
                'query_keys' => array_keys($_REQUEST ?? []),
            ]);
            $this->errorResponse('failed to fetch lead assignment', 500);
        }
    }

    public function getLeadVipAccess(): void
    {
        try {
            $this->assertAuthorized('get_lead_vip_access');
            $criteria = $this->extractLookupCriteria();
            $row = $this->findLeadForExternalLookup($criteria);

            if (!$row) {
                $this->successResponse(array_merge(
                    $this->buildMissingLeadResponse(),
                    ['vip' => $this->serviceGovernanceRepo->resolveVipAccessByContactId('')]
                ));
            }

            $this->successResponse(array_merge(
                $this->buildLeadAssignmentPayload($row),
                ['vip' => $this->serviceGovernanceRepo->resolveVipAccessByContactId((string)($row['didar_contact_id'] ?? ''))]
            ));
        } catch (\Throwable $e) {
            Logger::logError('External VIP access lookup failed', $e, [
                'query_keys' => array_keys($_REQUEST ?? []),
            ]);
            $this->errorResponse('failed to fetch vip access profile', 500);
        }
    }

    public function reconcileAppLead(): void
    {
        try {
            $this->assertAuthorized('reconcile_app_lead');
            $criteria = $this->extractLookupCriteria();
            $row = $this->findLeadForExternalLookup($criteria);
            $created = false;

            if (!$row) {
                $person = $this->createAppLeadFromRequest($criteria);
                $created = true;
                $row = $this->findLeadForExternalLookup([
                    'didar_contact_id' => (string)$person->didar_contact_id,
                    'customer_code' => '',
                    'national_id' => '',
                    'phone' => (string)($person->mobile_phone ?? ''),
                    'phone_candidates' => PhoneNormalizer::normalizeCandidates((string)($person->mobile_phone ?? '')),
                ]);
            }

            if (!$row) {
                $this->errorResponse('failed to reconcile app lead', 500);
            }

            $payload = $this->buildLeadAssignmentPayload($row);
            $payload['created'] = $created;
            $payload['lead_source'] = $created ? trim((string)$this->configRepo->getValue('app_source_code', 'mobile_app')) : null;
            $payload['vip'] = $this->serviceGovernanceRepo->resolveVipAccessByContactId((string)($row['didar_contact_id'] ?? ''));

            $this->successResponse($payload);
        } catch (\Throwable $e) {
            Logger::logError('External app lead reconciliation failed', $e, [
                'query_keys' => array_keys($_REQUEST ?? []),
            ]);
            $this->errorResponse('failed to reconcile app lead', 500);
        }
    }

    private function assertAuthorized(string $endpoint): void
    {
        $enabled = $this->normalizeFlag($this->configRepo->getValue('external_api_enabled', '0'));
        if (!$enabled) {
            $this->errorResponse('external API is disabled', 503);
        }

        $configuredToken = trim((string)($this->configRepo->getValue('external_api_token', getenv('EXTERNAL_API_TOKEN') ?: '')));
        if ($configuredToken === '') {
            $this->errorResponse('external API token is not configured', 503);
        }

        $providedToken = $this->extractToken();
        if ($providedToken === '' || !hash_equals($configuredToken, $providedToken)) {
            Logger::logWarning('External API token mismatch', [
                'endpoint' => $endpoint,
                'ip' => $_SERVER['REMOTE_ADDR'] ?? '',
            ]);
            $this->errorResponse('unauthorized', 401);
        }
    }

    private function extractLookupCriteria(): array
    {
        $phone = Sanitizer::sanitize($_REQUEST['phone'] ?? '');
        $didarContactId = Sanitizer::sanitize($_REQUEST['didar_contact_id'] ?? '');
        $customerCode = Sanitizer::sanitize($_REQUEST['customer_code'] ?? '');
        $nationalId = Sanitizer::sanitize($_REQUEST['national_id'] ?? '');
        $phoneCandidates = $phone !== '' ? PhoneNormalizer::normalizeCandidates($phone) : [];

        if ($phone === '' && $didarContactId === '' && $customerCode === '' && $nationalId === '') {
            $this->errorResponse('one of phone, didar_contact_id, customer_code, or national_id is required', 422);
        }

        return [
            'phone' => $phone,
            'phone_candidates' => $phoneCandidates,
            'didar_contact_id' => $didarContactId,
            'customer_code' => $customerCode,
            'national_id' => $nationalId,
        ];
    }

    private function findLeadForExternalLookup(array $criteria): ?array
    {
        return $this->personRepo->findLeadAssignmentForExternalLookup([
            'phone_candidates' => $criteria['phone_candidates'] ?? [],
            'didar_contact_id' => $criteria['didar_contact_id'] ?? '',
            'customer_code' => $criteria['customer_code'] ?? '',
            'national_id' => $criteria['national_id'] ?? '',
        ]);
    }

    private function buildMissingLeadResponse(): array
    {
        return [
            'lead_found' => false,
            'assigned' => false,
            'has_agent' => false,
            'sales_agent_name' => null,
            'match_type' => null,
            'lead' => null,
            'sales_agent' => null,
        ];
    }

    private function buildLeadAssignmentPayload(array $row): array
    {
        $leadName = trim((string)($row['first_name'] ?? '') . ' ' . (string)($row['last_name'] ?? ''));
        $hasOwner = trim((string)($row['owner_didar_id'] ?? '')) !== '';
        $ownerName = trim((string)($row['owner_name'] ?? ''));

        return [
            'lead_found' => true,
            'assigned' => $hasOwner,
            'has_agent' => $hasOwner,
            'sales_agent_name' => $hasOwner && $ownerName !== '' ? $ownerName : null,
            'match_type' => $row['match_type'] ?: null,
            'lead' => [
                'id' => isset($row['id']) ? (int)$row['id'] : null,
                'didar_contact_id' => $row['didar_contact_id'] ?: null,
                'customer_code' => $row['customer_code'] ?: null,
                'name' => $leadName !== '' ? $leadName : null,
                'mobile_phone' => $row['mobile_phone'] ?: null,
                'owner_didar_id' => $row['owner_didar_id'] ?: null,
            ],
            'sales_agent' => $hasOwner ? [
                'id' => isset($row['owner_user_id']) ? (int)$row['owner_user_id'] : null,
                'didar_user_id' => $row['owner_user_didar_id'] ?: ($row['owner_didar_id'] ?: null),
                'name' => $ownerName !== '' ? $ownerName : null,
                'first_name' => $row['owner_first_name'] ?: null,
                'last_name' => $row['owner_last_name'] ?: null,
                'email' => $row['owner_email'] ?: null,
                'role' => $row['owner_role'] ?: null,
                'is_active' => isset($row['owner_is_active']) ? (bool)$row['owner_is_active'] : null,
            ] : null,
        ];
    }

    private function createAppLeadFromRequest(array $criteria): Person
    {
        $ownerDidarId = trim((string)$this->configRepo->getValue('app_default_owner_didar_id', ''));
        if ($ownerDidarId === '') {
            $this->errorResponse('app default owner is not configured', 503);
        }

        $phone = trim((string)($criteria['phone'] ?? ''));
        if ($phone === '') {
            $this->errorResponse('phone is required for app lead creation', 422);
        }

        $normalizedPhone = PhoneNormalizer::normalize($phone);
        $fullName = trim((string)Sanitizer::sanitize($_REQUEST['full_name'] ?? ''));
        $firstName = trim((string)Sanitizer::sanitize($_REQUEST['first_name'] ?? ''));
        $lastName = trim((string)Sanitizer::sanitize($_REQUEST['last_name'] ?? ''));
        if ($fullName !== '' && ($firstName === '' || $lastName === '')) {
            $parts = preg_split('/\s+/u', $fullName, 2) ?: [];
            $firstName = $firstName !== '' ? $firstName : trim((string)($parts[0] ?? ''));
            $lastName = $lastName !== '' ? $lastName : trim((string)($parts[1] ?? ''));
        }
        if ($firstName === '' && $lastName === '') {
            $firstName = 'کاربر';
            $lastName = 'اپ';
        } elseif ($lastName === '') {
            $lastName = $firstName;
        }

        $appSourceCode = trim((string)$this->configRepo->getValue('app_source_code', 'mobile_app'));
        $appName = trim((string)Sanitizer::sanitize($_REQUEST['app_name'] ?? ''));
        $email = trim((string)Sanitizer::sanitize($_REQUEST['email'] ?? ''));
        $city = trim((string)Sanitizer::sanitize($_REQUEST['city'] ?? ''));
        $nationalId = trim((string)($criteria['national_id'] ?? ''));
        $requestedServices = trim((string)($_REQUEST['requested_services'] ?? ''));
        $registerTime = date('Y-m-d H:i:s');

        $rawJson = [
            'local_only' => true,
            'created_at' => $registerTime,
            'created_via' => 'external_api',
            'source_system' => $appSourceCode !== '' ? $appSourceCode : 'mobile_app',
            'source_app_name' => $appName !== '' ? $appName : null,
        ];

        $person = new Person([
            'didar_contact_id' => uniqid('local_', true),
            'owner_didar_id' => $ownerDidarId,
            'previous_owner_id' => null,
            'code' => '',
            'customer_code' => trim((string)Sanitizer::sanitize($_REQUEST['customer_code'] ?? '')),
            'first_name' => $firstName,
            'last_name' => $lastName,
            'mobile_phone' => $normalizedPhone,
            'secondary_mobile_phone' => null,
            'mobile_phone_3' => null,
            'mobile_phone_4' => null,
            'work_phone' => null,
            'email' => $email !== '' ? $email : null,
            'contact_type' => 'Lead',
            'city' => $city !== '' ? $city : null,
            'job_title' => null,
            'job_description' => null,
            'acquaintance_source' => $appSourceCode !== '' ? $appSourceCode : 'mobile_app',
            'acquaintance_detail' => $appName !== '' ? $appName : 'external_app',
            'content_topic' => null,
            'national_id' => $nationalId !== '' ? $nationalId : null,
            'has_previous_purchase' => null,
            'sale_status' => 0,
            'register_time' => $registerTime,
            'register_time_jalali' => null,
            'visibility_type' => '',
            'background_info' => null,
            'customer_products' => $requestedServices,
            'requested_services' => $requestedServices !== '' ? $requestedServices : null,
            'last_sync' => $registerTime,
            'raw_json' => json_encode($rawJson, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
        ]);

        $newId = $this->personRepo->save($person);
        $person->id = $newId;
        return $person;
    }

    private function normalizeFlag($value): bool
    {
        $normalized = is_string($value) ? strtolower(trim($value)) : $value;
        return in_array($normalized, [1, '1', true, 'true', 'on', 'yes'], true);
    }

    private function extractToken(): string
    {
        $header = $_SERVER['HTTP_AUTHORIZATION'] ?? $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ?? '';
        if (is_string($header) && preg_match('/Bearer\s+(.+)/i', $header, $matches)) {
            return trim((string)$matches[1]);
        }

        $headerToken = $_SERVER['HTTP_X_API_TOKEN'] ?? '';
        if (is_string($headerToken) && trim($headerToken) !== '') {
            return trim($headerToken);
        }

        return trim((string)($_REQUEST['token'] ?? ''));
    }
}
