<?php
namespace App\Controllers;

use App\Services\AuthService;
use App\Services\LeadService;
use App\Repositories\PersonRepository;
use App\Repositories\UserRepository;
use App\Utils\PhoneNormalizer;
use App\Utils\Validator;
use PhpOffice\PhpSpreadsheet\IOFactory;

class ImportController extends ApiController
{
    private AuthService $authService;
    private LeadService $leadService;
    private PersonRepository $personRepo;
    private UserRepository $userRepo;

    public function __construct(
        AuthService $authService,
        LeadService $leadService,
        PersonRepository $personRepo,
        UserRepository $userRepo
    ) {
        $this->authService = $authService;
        $this->leadService = $leadService;
        $this->personRepo = $personRepo;
        $this->userRepo = $userRepo;
    }

    public function downloadLeadsImportTemplate()
    {
        if (!$this->authService->isAdmin()) {
            $this->errorResponse('فقط مدیر می‌تواند فایل نمونه را دانلود کند');
            return;
        }

        $headers = [
            'mobile_phone',
            'owner_username',
            'full_name',
            'city',
            'acquaintance_source',
            'acquaintance_detail',
            'content_topic'
        ];
        $sample = [
            '9123456789',
            'shakiba',
            'نمونه کاربر',
            'تهران',
            'اینستاگرام',
            'پیج آموزشی',
            'KPI'
        ];

        $filename = 'lead_import_template.csv';
        header('Content-Type: text/csv; charset=UTF-8');
        header('Content-Disposition: attachment; filename="' . $filename . '"');
        echo "\xEF\xBB\xBF";
        echo implode(',', $headers) . "\n";
        echo implode(',', array_map(static function ($cell) {
            $value = (string)$cell;
            if (strpos($value, ',') !== false || strpos($value, '"') !== false || strpos($value, "\n") !== false) {
                return '"' . str_replace('"', '""', $value) . '"';
            }
            return $value;
        }, $sample)) . "\n";
    }

    /**
     * پیش‌نمایش فایل ایمپورت لید
     */
    public function importLeadsPreview()
    {
        if (!$this->authService->isAdmin()) {
            $this->errorResponse('فقط مدیر می‌تواند لیدها را وارد کند');
            return;
        }

        try {
            [$rows, $headerMap] = $this->loadImportRowsFromUpload();
            $preview = [];
            $validCount = 0;
            foreach ($rows as $idx => $row) {
                $rowNumber = $idx + 2;
                if ($this->isRowEmpty($row)) {
                    continue;
                }
                $rowData = $this->extractImportRow($row, $headerMap, $rowNumber);
                $errors = $this->validateImportRow($rowData);
                if (empty($errors)) $validCount++;
                $rowData['errors'] = $errors;
                $preview[] = $rowData;
            }

            $this->successResponse([
                'preview' => $preview,
                'valid_count' => $validCount,
                'error_count' => max(0, count($preview) - $validCount)
            ]);
        } catch (\Throwable $e) {
            $this->errorResponse('خطا در پردازش فایل: ' . $e->getMessage());
        }
    }

    /**
     * اجرای واقعی ایمپورت لید/معامله
     */
    public function importLeadsExecute()
    {
        if (!$this->authService->isAdmin()) {
            $this->errorResponse('فقط مدیر می‌تواند لیدها را وارد کند');
            return;
        }

        try {
            [$rows, $headerMap] = $this->loadImportRowsFromUpload();
            $leadCreatedCount = 0;
            $dealCreatedCount = 0;
            $skippedCount = 0;
            $results = [];
            foreach ($rows as $idx => $row) {
                $rowNumber = $idx + 2;
                if ($this->isRowEmpty($row)) continue;

                $rowData = $this->extractImportRow($row, $headerMap, $rowNumber);
                $errors = $this->validateImportRow($rowData);
                if (!empty($errors)) {
                    $skippedCount++;
                    $results[] = $this->buildImportResult($rowData, 'fail', 'skip', implode(' | ', $errors));
                    continue;
                }

                $owner = $this->resolveOwnerByUsername($rowData['owner_username']);
                if (!$owner || empty($owner->didar_user_id)) {
                    $skippedCount++;
                    $results[] = $this->buildImportResult($rowData, 'fail', 'skip', "مسئول با username '{$rowData['owner_username']}' یافت نشد");
                    continue;
                }

                $ownerDidarId = (string)$owner->didar_user_id;
                $ownerDisplay = trim((string)($owner->display_name ?? ($owner->first_name . ' ' . $owner->last_name)));

                $existingPerson = $this->personRepo->findByPhone(PhoneNormalizer::normalizeCandidates($rowData['mobile_phone']));
                if ($existingPerson) {
                    $existingOwnerDidarId = (string)($existingPerson->owner_didar_id ?? '');
                    if ($existingOwnerDidarId !== $ownerDidarId) {
                        $skippedCount++;
                        $existingOwnerName = $this->resolveOwnerName($existingOwnerDidarId);
                        $results[] = $this->buildImportResult(
                            $rowData,
                            'fail',
                            'skip',
                            "شماره قبلاً ثبت شده و متعلق به کاربر دیگری است ({$existingOwnerName})",
                            $ownerDisplay
                        );
                        continue;
                    }

                    $deal = $this->leadService->createAdditionalDealForContact(
                        (string)$existingPerson->didar_contact_id,
                        $ownerDidarId
                    );
                    if ($deal) {
                        $dealCreatedCount++;
                        $results[] = $this->buildImportResult(
                            $rowData,
                            'success',
                            'deal_created',
                            'لید قبلاً وجود داشت؛ معامله جدید ایجاد شد',
                            $ownerDisplay,
                            [
                                'didar_contact_id' => (string)($existingPerson->didar_contact_id ?? ''),
                                'didar_deal_id' => (string)($deal->didar_deal_id ?? '')
                            ]
                        );
                    } else {
                        $skippedCount++;
                        $results[] = $this->buildImportResult(
                            $rowData,
                            'fail',
                            'skip',
                            'لید تکراری بود ولی ایجاد معامله جدید ناموفق شد',
                            $ownerDisplay
                        );
                    }
                    continue;
                }

                $leadPayload = [
                    'full_name' => $rowData['full_name'] !== '' ? $rowData['full_name'] : 'لید جدید',
                    'mobile_phone' => $rowData['mobile_phone'],
                    'owner_didar_id' => $ownerDidarId,
                    'city' => $rowData['city'],
                    'acquaintance_source' => $rowData['acquaintance_source'],
                    'acquaintance_detail' => $rowData['acquaintance_detail'],
                    'content_topic' => $rowData['content_topic']
                ];

                try {
                    $created = $this->leadService->createLead($leadPayload, false);
                    if (!empty($created['is_duplicate'])) {
                        $duplicateOwnerId = (string)($created['owner_id'] ?? '');
                        if ($duplicateOwnerId !== '' && $duplicateOwnerId === $ownerDidarId) {
                            $deal = $this->leadService->createAdditionalDealForContact(
                                (string)($created['didar_contact_id'] ?? ''),
                                $ownerDidarId
                            );
                            if ($deal) {
                                $dealCreatedCount++;
                                $results[] = $this->buildImportResult(
                                    $rowData,
                                    'success',
                                    'deal_created',
                                    'لید تکراری (همان مسئول)؛ معامله جدید ایجاد شد',
                                    $ownerDisplay,
                                    [
                                        'didar_contact_id' => (string)($created['didar_contact_id'] ?? ''),
                                        'didar_deal_id' => (string)($deal->didar_deal_id ?? '')
                                    ]
                                );
                            } else {
                                $skippedCount++;
                                $results[] = $this->buildImportResult($rowData, 'fail', 'skip', 'تشخیص تکراری انجام شد ولی ساخت معامله ناموفق بود', $ownerDisplay);
                            }
                        } else {
                            $skippedCount++;
                            $existingOwnerName = $this->resolveOwnerName($duplicateOwnerId);
                            $results[] = $this->buildImportResult($rowData, 'fail', 'skip', "شماره تکراری و متعلق به کاربر دیگر است ({$existingOwnerName})", $ownerDisplay);
                        }
                        continue;
                    }

                    $leadCreatedCount++;
                    $results[] = $this->buildImportResult(
                        $rowData,
                        'success',
                        'lead_created',
                        'لید جدید با موفقیت ثبت شد',
                        $ownerDisplay,
                        [
                            'didar_contact_id' => (string)($created['didar_contact_id'] ?? ''),
                            'didar_deal_id' => (string)($created['deal_id'] ?? '')
                        ]
                    );
                } catch (\Throwable $e) {
                    $skippedCount++;
                    $results[] = $this->buildImportResult($rowData, 'fail', 'skip', 'خطا: ' . $e->getMessage(), $ownerDisplay);
                }
            }

            $this->successResponse([
                'lead_created_count' => $leadCreatedCount,
                'deal_created_count' => $dealCreatedCount,
                'skipped_count' => $skippedCount,
                'success_count' => $leadCreatedCount + $dealCreatedCount,
                'failure_count' => $skippedCount,
                'results' => $results
            ]);
        } catch (\Throwable $e) {
            $this->errorResponse('خطا: ' . $e->getMessage());
        }
    }

    private function loadImportRowsFromUpload(): array
    {
        if (!isset($_FILES['file']) || $_FILES['file']['error'] !== UPLOAD_ERR_OK) {
            throw new \RuntimeException('فایلی آپلود نشده است');
        }

        $file = $_FILES['file'];
        $allowedExtensions = ['xlsx', 'xls', 'csv'];
        $fileExtension = strtolower(pathinfo((string)$file['name'], PATHINFO_EXTENSION));
        if (!in_array($fileExtension, $allowedExtensions, true)) {
            throw new \RuntimeException('فقط فایل‌های Excel یا CSV قابل پذیرش هستند');
        }
        if ((int)$file['size'] > 5 * 1024 * 1024) {
            throw new \RuntimeException('حجم فایل نباید بیشتر از 5 مگابایت باشد');
        }

        $rows = [];
        if ($fileExtension === 'csv') {
            $rows = $this->readCsvRows((string)$file['tmp_name']);
        } else {
            if (!class_exists('\PhpOffice\PhpSpreadsheet\IOFactory')) {
                throw new \RuntimeException('کتابخانه Excel روی سرور نصب نیست. لطفاً فایل CSV آپلود کنید.');
            }
            $spreadsheet = IOFactory::load((string)$file['tmp_name']);
            $worksheet = $spreadsheet->getActiveSheet();
            $rows = $worksheet->toArray('', true, true, false);
        }
        if (empty($rows)) {
            throw new \RuntimeException('فایل خالی است');
        }

        $header = array_map(static function ($value) {
            return trim((string)$value);
        }, (array)($rows[0] ?? []));

        $mobileAliases = ['mobile_phone', 'mobile', 'phone', 'شماره موبایل', 'شماره', 'موبایل', 'شماره تماس'];
        $ownerAliases = ['owner_username', 'username', 'owner', 'نام کاربری مسئول', 'یوزرنیم مسئول', 'مسئول'];

        $mobileIdx = $this->findHeaderIndex($header, $mobileAliases);
        $ownerIdx = $this->findHeaderIndex($header, $ownerAliases);
        if ($mobileIdx < 0 || $ownerIdx < 0) {
            throw new \RuntimeException('ستون‌های الزامی یافت نشد. ستون‌های الزامی: mobile_phone و owner_username');
        }

        $headerMap = [
            'mobile_phone' => $mobileIdx,
            'owner_username' => $ownerIdx,
            'full_name' => $this->findHeaderIndex($header, ['full_name', 'name', 'نام و نام خانوادگی', 'نام']),
            'city' => $this->findHeaderIndex($header, ['city', 'شهر']),
            'acquaintance_source' => $this->findHeaderIndex($header, ['acquaintance_source', 'source', 'شیوه آشنایی']),
            'acquaintance_detail' => $this->findHeaderIndex($header, ['acquaintance_detail', 'source_detail', 'جزئیات شیوه آشنایی']),
            'content_topic' => $this->findHeaderIndex($header, ['content_topic', 'topic', 'موضوع محتوا'])
        ];

        return [array_slice($rows, 1), $headerMap];
    }

    private function readCsvRows(string $path): array
    {
        $lines = @file($path, FILE_IGNORE_NEW_LINES);
        if ($lines === false || empty($lines)) {
            throw new \RuntimeException('امکان خواندن فایل CSV وجود ندارد');
        }

        $normalizeLine = static function (string $line): string {
            $line = preg_replace('/^\xEF\xBB\xBF/u', '', $line);
            if (function_exists('mb_detect_encoding')) {
                $preferred = ['UTF-8', 'UTF-16LE', 'UTF-16BE', 'CP1256', 'Windows-1252', 'ISO-8859-1'];
                $available = function_exists('mb_list_encodings') ? (array)mb_list_encodings() : [];
                $preferredLower = array_map('strtolower', $preferred);
                $availableMap = [];
                foreach ($available as $encName) {
                    $availableMap[strtolower((string)$encName)] = (string)$encName;
                }
                $usable = [];
                foreach ($preferredLower as $encLower) {
                    if (isset($availableMap[$encLower])) {
                        $usable[] = $availableMap[$encLower];
                    }
                }
                if (!empty($usable)) {
                    $enc = mb_detect_encoding($line, $usable, true);
                    if ($enc && strtoupper($enc) !== 'UTF-8') {
                        $converted = @mb_convert_encoding($line, 'UTF-8', $enc);
                        if (is_string($converted) && $converted !== '') {
                            $line = $converted;
                        }
                    }
                }
            }
            return $line;
        };

        $firstLine = $normalizeLine((string)$lines[0]);
        $candidates = [',', ';', "\t", '|'];
        $delimiter = ',';
        $maxParts = 0;
        foreach ($candidates as $candidate) {
            $parts = str_getcsv($firstLine, $candidate);
            $count = is_array($parts) ? count($parts) : 0;
            if ($count > $maxParts) {
                $maxParts = $count;
                $delimiter = $candidate;
            }
        }

        $rows = [];
        foreach ($lines as $line) {
            $line = $normalizeLine((string)$line);
            $parsed = str_getcsv($line, $delimiter);
            if ($parsed === null) {
                continue;
            }
            $rows[] = array_map(static function ($cell) {
                $value = is_string($cell) ? trim($cell) : (string)$cell;
                return preg_replace('/^\xEF\xBB\xBF/u', '', $value);
            }, $parsed);
        }

        return $rows;
    }

    private function findHeaderIndex(array $headers, array $aliases): int
    {
        $normalizedAliases = array_map([$this, 'normalizeHeaderText'], $aliases);
        foreach ($headers as $index => $name) {
            $normalized = $this->normalizeHeaderText((string)$name);
            if (in_array($normalized, $normalizedAliases, true)) {
                return (int)$index;
            }
        }
        return -1;
    }

    private function normalizeHeaderText(string $value): string
    {
        $v = preg_replace('/^\xEF\xBB\xBF/u', '', $value);
        $v = str_replace(['-', '–', '—', 'ـ', ' '], '_', $v);
        $v = preg_replace('/_+/', '_', $v);
        $v = trim($v, "_ \t\n\r\0\x0B");
        return mb_strtolower($v);
    }

    private function extractImportRow(array $row, array $headerMap, int $rowNumber): array
    {
        $get = static function (array $data, int $idx): string {
            if ($idx < 0) return '';
            return trim((string)($data[$idx] ?? ''));
        };
        $mobileRaw = $get($row, (int)$headerMap['mobile_phone']);
        $ownerUsername = $get($row, (int)$headerMap['owner_username']);
        $mobileDigits = preg_replace('/\D+/', '', $mobileRaw);
        if (strlen($mobileDigits) === 11 && strpos($mobileDigits, '0') === 0) {
            $mobileDigits = substr($mobileDigits, 1);
        }
        return [
            'row_number' => $rowNumber,
            'mobile_phone' => (string)$mobileDigits,
            'owner_username' => $ownerUsername,
            'full_name' => $get($row, (int)$headerMap['full_name']),
            'city' => $get($row, (int)$headerMap['city']),
            'acquaintance_source' => $get($row, (int)$headerMap['acquaintance_source']),
            'acquaintance_detail' => $get($row, (int)$headerMap['acquaintance_detail']),
            'content_topic' => $get($row, (int)$headerMap['content_topic'])
        ];
    }

    private function validateImportRow(array $rowData): array
    {
        $errors = [];
        if (empty($rowData['mobile_phone'])) {
            $errors[] = 'شماره موبایل خالی است';
        } else {
            $validation = Validator::validatePhone($rowData['mobile_phone'], 'شماره موبایل');
            if (!$validation['valid']) {
                $errors[] = $validation['message'];
            } else {
                $rowData['mobile_phone'] = $validation['cleaned'] ?? $rowData['mobile_phone'];
            }
        }
        if (empty($rowData['owner_username'])) {
            $errors[] = 'نام کاربری مسئول خالی است';
        }
        return $errors;
    }

    private function resolveOwnerByUsername(string $username)
    {
        $normalized = trim($username);
        if ($normalized === '') return null;
        return $this->userRepo->findByUsernameOrDisplayName($normalized);
    }

    private function resolveOwnerName(string $ownerDidarId): string
    {
        if ($ownerDidarId === '') return 'نامشخص';
        $owner = $this->userRepo->findByDidarId($ownerDidarId);
        if (!$owner) return $ownerDidarId;
        $name = trim((string)($owner->display_name ?? (($owner->first_name ?? '') . ' ' . ($owner->last_name ?? ''))));
        return $name !== '' ? $name : $ownerDidarId;
    }

    private function buildImportResult(array $rowData, string $status, string $action, string $message, string $ownerDisplayName = '', array $extra = []): array
    {
        return array_merge([
            'row' => (int)($rowData['row_number'] ?? 0),
            'status' => $status,
            'action' => $action,
            'mobile_phone' => (string)($rowData['mobile_phone'] ?? ''),
            'owner_username' => (string)($rowData['owner_username'] ?? ''),
            'owner_name' => $ownerDisplayName,
            'message' => $message
        ], $extra);
    }

    private function isRowEmpty(array $row): bool
    {
        foreach ($row as $cell) {
            if (trim((string)$cell) !== '') return false;
        }
        return true;
    }
}


