<?php
namespace App\Controllers;

use App\Repositories\UserRepository;
use App\Repositories\ConfigRepository;
use App\Services\AuthService;
use App\Services\DidarApiService;
use App\Services\UserHierarchyService;
use App\Database\Connection;
use App\Utils\Sanitizer;
use PDO;

class UserController extends ApiController
{
    private $userRepo;
    private $authService;
    private $didarApi;
    private $db;
    private $configRepo;
    private $userHierarchyService;

    public function __construct(UserRepository $userRepo, AuthService $authService, ?DidarApiService $didarApi = null, ?Connection $db = null, ?ConfigRepository $configRepo = null, ?UserHierarchyService $userHierarchyService = null)
    {
        $this->userRepo = $userRepo;
        $this->authService = $authService;
        $this->configRepo = $configRepo;
        $this->userHierarchyService = $userHierarchyService;
        
        // Get from global app if not provided (for backward compatibility)
        if ($didarApi === null || $db === null) {
            global $app;
            if (!isset($app)) {
                $app = $GLOBALS['app'] ?? null;
            }
            if ($app) {
                $this->didarApi = $didarApi ?? $app->services->didarApi;
                $this->db = $db ?? $app->db;
                $this->configRepo = $configRepo ?? ($app->repositories->config ?? null);
                $this->userHierarchyService = $userHierarchyService ?? ($app->services->userHierarchy ?? null);
            }
        } else {
            $this->didarApi = $didarApi;
            $this->db = $db;
            $this->configRepo = $configRepo;
            if ($this->userHierarchyService === null) {
                global $app;
                $this->userHierarchyService = $app->services->userHierarchy ?? null;
            }
        }
    }

    private function isValidRoleKey(string $role): bool
    {
        $role = trim($role);
        if ($role === '') {
            return false;
        }

        if (in_array($role, ['admin', 'agent', 'crm_specialist', 'accountant'], true)) {
            return true;
        }

        global $app;
        if (isset($app->services->rbac) && $app->services->rbac) {
            try {
                $catalog = $app->services->rbac->getCatalog();
                foreach ((array)($catalog['roles'] ?? []) as $rbacRole) {
                    if ((string)($rbacRole['role_key'] ?? '') === $role && (int)($rbacRole['is_active'] ?? 1) === 1) {
                        return true;
                    }
                }
            } catch (\Throwable $e) {
                // Fallback to built-ins only if RBAC catalog unavailable.
            }
        }

        return false;
    }

    private function requireAdminOrDelegated(string $capabilityKey): void
    {
        if (!$this->authService->isAdmin() && !$this->hasDelegatedCapability($capabilityKey)) {
            $this->errorResponse('دسترسی محدود به مدیر سیستم');
        }
    }

    /**
     * Public: Get login users list (for username dropdown on login page).
     * DOES NOT require authentication.
     */
    public function getLoginUsers()
    {
        $users = $this->userRepo->getLoginUsers();
        $this->successResponse(['users' => $users]);
    }

    public function getList()
    {
        $this->requireAdminOrDelegated('users.admin.view');
        
        $users = $this->userRepo->getAll();
        $usersArray = array_map(function($user) {
            return $user->toArray();
        }, $users);
        
        $this->successResponse([
            'users' => $usersArray,
            'hierarchy_assignments' => $this->userHierarchyService ? $this->userHierarchyService->listAssignments() : [],
            'master_password_configured' => $this->configRepo ? ($this->configRepo->getValue('master_password_hash', '') !== '') : false
        ]);
    }

    public function getHierarchyAssignments()
    {
        $this->requireAdminOrDelegated('users.admin.view');
        if (!$this->userHierarchyService) {
            $this->errorResponse('سرویس ساختار سازمانی در دسترس نیست');
        }

        $userId = (int)($_POST['user_id'] ?? $_GET['user_id'] ?? 0);
        $this->successResponse([
            'hierarchy_assignments' => $this->userHierarchyService->listAssignments($userId),
        ]);
    }

    public function saveHierarchyAssignment()
    {
        $this->requireAdminOrDelegated('users.admin.edit');
        if (!$this->userHierarchyService) {
            $this->errorResponse('سرویس ساختار سازمانی در دسترس نیست');
        }

        try {
            $id = $this->userHierarchyService->saveAssignment([
                'user_id' => $_POST['user_id'] ?? 0,
                'supervisor_user_id' => $_POST['supervisor_user_id'] ?? null,
                'manager_user_id' => $_POST['manager_user_id'] ?? null,
                'supervisor_commission_rate_percent' => $_POST['supervisor_commission_rate_percent'] ?? null,
                'manager_commission_rate_percent' => $_POST['manager_commission_rate_percent'] ?? null,
                'effective_from' => $_POST['effective_from'] ?? '',
                'effective_to' => $_POST['effective_to'] ?? '',
            ], (int)($_SESSION['user_id'] ?? 0));

            $this->successResponse([
                'id' => $id,
                'hierarchy_assignments' => $this->userHierarchyService->listAssignments(),
            ], 'ساختار سازمانی ذخیره شد');
        } catch (\InvalidArgumentException $e) {
            $this->errorResponse($e->getMessage());
        } catch (\Throwable $e) {
            \App\Utils\Logger::logError('Failed to save user hierarchy assignment', $e);
            $this->errorResponse('خطا در ذخیره ساختار سازمانی');
        }
    }

    public function deleteHierarchyTeam()
    {
        $this->requireAdminOrDelegated('users.admin.edit');
        if (!$this->userHierarchyService) {
            $this->errorResponse('سرویس ساختار سازمانی در دسترس نیست');
        }

        try {
            $deleted = $this->userHierarchyService->deleteTeamAssignments(
                (int)($_POST['owner_user_id'] ?? 0),
                (string)($_POST['team_type'] ?? 'sales')
            );
            $this->successResponse([
                'deleted' => $deleted,
                'hierarchy_assignments' => $this->userHierarchyService->listAssignments(),
            ], 'تیم حذف شد');
        } catch (\InvalidArgumentException $e) {
            $this->errorResponse($e->getMessage());
        } catch (\Throwable $e) {
            \App\Utils\Logger::logError('Failed to delete hierarchy team', $e);
            $this->errorResponse('خطا در حذف تیم');
        }
    }

    public function getOne()
    {
        $this->requireAdminOrDelegated('users.admin.view');

        $userId = (int)($_POST['user_id'] ?? $_GET['user_id'] ?? 0);
        if ($userId <= 0) {
            $this->errorResponse('شناسه کاربر الزامی است');
        }

        $user = $this->userRepo->findById($userId);
        if (!$user) {
            $this->errorResponse('کاربر یافت نشد', 404);
        }

        $this->successResponse(['user' => $user->toArray()]);
    }

    /**
     * Sync users from Didar API and update their didar_user_ids
     * This ensures OwnerId in activities is correct
     */
    public function syncDidarUsers()
    {
        $this->requireAdminOrDelegated('users.admin.sync_didar');
        
        if (!$this->didarApi) {
            $this->errorResponse('سرویس Didar API در دسترس نیست');
        }
        
        try {
            // Fetch users from Didar API
            $didarUsers = $this->didarApi->syncDidarUsers();
            
            if ($didarUsers === false) {
                $this->errorResponse('خطا در دریافت کاربران از Didar. لطفاً لاگ‌ها را بررسی کنید.');
            }
            
            if (!is_array($didarUsers) || empty($didarUsers)) {
                $this->errorResponse('هیچ کاربری از Didar دریافت نشد. لطفاً API Key را بررسی کنید.');
            }
            
            $updated = 0;
            $notFound = 0;
            
            // Update each user with their Didar UserId
            foreach ($didarUsers as $didarUser) {
                $userId = $didarUser['Id'] ?? null;
                $email = $didarUser['Email'] ?? null;
                $firstName = $didarUser['FirstName'] ?? '';
                $lastName = $didarUser['LastName'] ?? '';
                $userName = $didarUser['UserName'] ?? null;
                
                if (!$userId) {
                    continue;
                }
                
                // Try to find user by email first
                $user = null;
                if ($email) {
                    $user = $this->userRepo->findByEmail($email);
                }
                
                // Try to find by display name if not found by email
                if (!$user && !empty($firstName) && !empty($lastName)) {
                    $displayName = $firstName . ' ' . $lastName;
                    $user = $this->userRepo->findByUsernameOrDisplayName($displayName);
                }
                
                if ($user) {
                    // Update user with correct Didar UserId
                    $user->didar_user_id = $userId;
                    $this->userRepo->save($user);
                    $updated++;
                } else {
                    $notFound++;
                }
            }
            
            $this->successResponse([
                'total_didar_users' => count($didarUsers),
                'updated' => $updated,
                'not_found' => $notFound
            ], "کاربران با موفقیت همگام‌سازی شدند. $updated کاربر به‌روزرسانی شد.");
        } catch (\Exception $e) {
            \App\Utils\Logger::logError("Failed to sync Didar users", $e);
            $this->errorResponse('خطا در همگام‌سازی کاربران: ' . $e->getMessage());
        }
    }

    public function save()
    {
        $this->requireAdminOrDelegated('users.admin.edit');

        $userId = (int)($_POST['user_id'] ?? 0);
        $email = Sanitizer::sanitize($_POST['email'] ?? '');
        $firstName = Sanitizer::sanitize($_POST['first_name'] ?? '');
        $lastName = Sanitizer::sanitize($_POST['last_name'] ?? '');
        $displayName = Sanitizer::sanitize($_POST['display_name'] ?? '');
        $username = Sanitizer::sanitize($_POST['username'] ?? '');
        $role = Sanitizer::sanitize($_POST['role'] ?? 'agent');
        $didarUserId = Sanitizer::sanitize($_POST['didar_user_id'] ?? '');
        $password = (string)($_POST['password'] ?? '');
        $passwordConfirm = (string)($_POST['password_confirm'] ?? '');

        if ($email === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
            $this->errorResponse('ایمیل معتبر الزامی است');
        }
        if ($firstName === '' || $lastName === '') {
            $this->errorResponse('نام و نام خانوادگی الزامی است');
        }
        if (!$this->isValidRoleKey($role)) {
            $this->errorResponse('نقش انتخاب‌شده نامعتبر است');
        }

        $existing = null;
        if ($userId > 0) {
            $existing = $this->userRepo->findById($userId);
            if (!$existing) {
                $this->errorResponse('کاربر برای ویرایش یافت نشد');
            }
        }

        $userByEmail = $this->userRepo->findByEmail($email);
        if ($userByEmail && (int)$userByEmail->id !== $userId) {
            $this->errorResponse('این ایمیل قبلاً برای کاربر دیگری ثبت شده است');
        }

        $isCreate = $existing === null;
        if ($isCreate || $password !== '' || $passwordConfirm !== '') {
            if ($password === '' || $passwordConfirm === '') {
                $this->errorResponse('رمز عبور و تکرار آن الزامی است');
            }
            if ($password !== $passwordConfirm) {
                $this->errorResponse('رمز عبور و تکرار آن یکسان نیستند');
            }
            if (mb_strlen($password) < 6) {
                $this->errorResponse('رمز عبور باید حداقل 6 کاراکتر باشد');
            }
        }

        if ($displayName === '') {
            $displayName = trim($firstName . ' ' . $lastName);
        }
        if ($username === '') {
            $username = $displayName !== '' ? $displayName : $email;
        }

        if ($didarUserId === '') {
            if ($existing && !empty($existing->didar_user_id)) {
                $didarUserId = (string)$existing->didar_user_id;
            } else {
                try {
                    $didarUserId = 'local_' . bin2hex(random_bytes(8));
                } catch (\Throwable $e) {
                    $didarUserId = 'local_' . uniqid('', true);
                }
            }
        }

        $user = new \App\Models\User([
            'id' => $userId ?: null,
            'didar_user_id' => $didarUserId,
            'email' => $email,
            'first_name' => $firstName,
            'last_name' => $lastName,
            'display_name' => $displayName,
            'username' => $username,
            'role' => $role,
            'is_active' => isset($_POST['is_active']) ? intval($_POST['is_active']) : 1
        ]);

        $this->userRepo->save($user);

        $savedUser = $this->userRepo->findByDidarId($didarUserId) ?: $this->userRepo->findByEmail($email);
        if ($savedUser && $password !== '') {
            $this->userRepo->updatePassword((int)$savedUser->id, password_hash($password, PASSWORD_DEFAULT));
        }

        $this->successResponse([
            'user' => $savedUser ? $savedUser->toArray() : null
        ], $isCreate ? 'کاربر جدید با موفقیت ایجاد شد' : 'کاربر با موفقیت ذخیره شد');
    }

    public function transferAllOwnership()
    {
        $this->requireAdminOrDelegated('users.admin.transfer_data');
        if (!$this->db) {
            $this->errorResponse('دیتابیس در دسترس نیست');
        }

        $fromUserId = Sanitizer::sanitize($_POST['from_user_didar_id'] ?? '');
        $toUserId = Sanitizer::sanitize($_POST['to_user_didar_id'] ?? '');

        if ($fromUserId === '' || $toUserId === '') {
            $this->errorResponse('کاربر مبدا و مقصد الزامی هستند');
        }
        if ($fromUserId === $toUserId) {
            $this->errorResponse('کاربر مبدا و مقصد نباید یکسان باشند');
        }

        $fromUser = $this->userRepo->findByDidarId($fromUserId);
        $toUser = $this->userRepo->findByDidarId($toUserId);
        if (!$fromUser || !$toUser) {
            $this->errorResponse('کاربر مبدا یا مقصد یافت نشد');
        }

        $pdo = $this->db->getPdo();
        $leadFilters = $this->buildLeadTransferFilters($_POST);
        $leadLimit = $this->normalizeLeadTransferLimit($_POST['lead_limit'] ?? null);
        $leadsOnly = (int)($_POST['leads_only'] ?? 0) === 1 || !empty($leadFilters) || $leadLimit !== null;
        $report = $leadsOnly
            ? $this->buildFilteredLeadTransferReport($fromUserId, $leadFilters, $leadLimit)
            : $this->buildTransferReport($fromUserId);

        if ((int)($_POST['preview'] ?? 0) === 1) {
            $this->successResponse([
                'from_user' => $fromUser->toArray(),
                'to_user' => $toUser->toArray(),
                'counts' => $report['counts'],
                'details' => $report['details'],
                'notes' => $report['notes']
            ]);
        }

        try {
            $pdo->beginTransaction();
            $updated = [];
            $targets = $this->getTransferTargets();
            if ($leadsOnly) {
                $targets = array_values(array_filter($targets, static function ($item) {
                    return $item['key'] === 'persons_owner';
                }));
            }

            foreach ($targets as $item) {
                if (!$this->db->hasColumn($item['table'], $item['column'])) {
                    continue;
                }
                if ($item['key'] === 'persons_owner') {
                    $updated[$item['key']] = [
                        'label' => $item['label'],
                        'updated' => $this->transferLeadOwnersWithHistory($pdo, $fromUserId, $toUserId, $leadFilters, $leadLimit)
                    ];
                } elseif ($item['key'] === 'deals_created_by' && $this->db->hasColumn('deals', 'created_by_name')) {
                    $stmt = $pdo->prepare("UPDATE deals SET created_by_didar_id = ?, created_by_name = ? WHERE created_by_didar_id = ?");
                    $stmt->execute([$toUserId, (string)($toUser->display_name ?: trim(($toUser->first_name ?? '') . ' ' . ($toUser->last_name ?? ''))), $fromUserId]);
                    $updated[$item['key']] = [
                        'label' => $item['label'],
                        'updated' => (int)$stmt->rowCount()
                    ];
                } else {
                    $stmt = $pdo->prepare("UPDATE {$item['table']} SET {$item['column']} = ? WHERE {$item['column']} = ?");
                    $stmt->execute([$toUserId, $fromUserId]);
                    $updated[$item['key']] = [
                        'label' => $item['label'],
                        'updated' => (int)$stmt->rowCount()
                    ];
                }
            }
            $pdo->commit();
        } catch (\Throwable $e) {
            if ($pdo->inTransaction()) {
                $pdo->rollBack();
            }
            \App\Utils\Logger::logError('Failed to transfer all user ownership', $e, [
                'from_user_didar_id' => $fromUserId,
                'to_user_didar_id' => $toUserId
            ]);
            $this->errorResponse('انتقال دیتا با خطا مواجه شد');
        }

        $this->successResponse([
            'from_user' => $fromUser->toArray(),
            'to_user' => $toUser->toArray(),
            'counts' => $updated,
            'details' => $report['details'],
            'notes' => $report['notes']
        ], 'مالکیت دیتا با موفقیت منتقل شد');
    }

    private function transferLeadOwnersWithHistory(\PDO $pdo, string $fromUserId, string $toUserId, array $filters = [], ?int $limit = null): int
    {
        $hasHistoryColumn = $this->db->hasColumn('persons', 'previous_owner_history');
        $selectColumns = $hasHistoryColumn
            ? "didar_contact_id, owner_didar_id, previous_owner_id, previous_owner_history"
            : "didar_contact_id, owner_didar_id, previous_owner_id";

        [$whereSql, $params] = $this->buildLeadTransferWhere($fromUserId, $filters);
        $sql = "SELECT {$selectColumns} FROM persons p WHERE {$whereSql} ORDER BY p.register_time DESC, p.created_at DESC, p.didar_contact_id ASC";
        if ($limit !== null) {
            $sql .= " LIMIT " . (int)$limit;
        }
        $stmt = $pdo->prepare($sql);
        $stmt->execute($params);
        $rows = $stmt->fetchAll(\PDO::FETCH_ASSOC) ?: [];
        if (empty($rows)) {
            return 0;
        }

        if ($hasHistoryColumn) {
            $update = $pdo->prepare("UPDATE persons SET owner_didar_id = ?, previous_owner_id = ?, previous_owner_history = ? WHERE didar_contact_id = ?");
        } else {
            $update = $pdo->prepare("UPDATE persons SET owner_didar_id = ?, previous_owner_id = ? WHERE didar_contact_id = ?");
        }

        $updated = 0;
        foreach ($rows as $row) {
            $currentOwnerId = trim((string)($row['owner_didar_id'] ?? ''));
            $previousOwnerId = trim((string)($row['previous_owner_id'] ?? ''));
            $history = $this->buildPreviousOwnerHistory(
                $hasHistoryColumn ? (string)($row['previous_owner_history'] ?? '') : '',
                $previousOwnerId,
                $currentOwnerId
            );

            if ($hasHistoryColumn) {
                $update->execute([
                    $toUserId,
                    $currentOwnerId !== '' ? $currentOwnerId : null,
                    $history,
                    (string)$row['didar_contact_id'],
                ]);
            } else {
                $update->execute([
                    $toUserId,
                    $currentOwnerId !== '' ? $currentOwnerId : null,
                    (string)$row['didar_contact_id'],
                ]);
            }
            $updated += (int)$update->rowCount();
        }

        return $updated;
    }

    private function buildPreviousOwnerHistory(string $existingHistory, string $previousOwnerId, string $currentOwnerId): ?string
    {
        $ids = [];
        foreach ([$existingHistory, $previousOwnerId, $currentOwnerId] as $source) {
            foreach (array_map('trim', explode(',', (string)$source)) as $value) {
                if ($value === '' || isset($ids[$value])) {
                    continue;
                }
                $ids[$value] = true;
            }
        }
        $history = array_keys($ids);
        return empty($history) ? null : implode(',', $history);
    }

    private function buildLeadTransferFilters(array $input): array
    {
        $filters = [];
        foreach ([
            'previous_owner_id',
            'sale_status',
            'product_id',
            'product_name',
            'requested_service',
            'content_topic',
            'customer_level',
            'search',
            'register_date_from',
            'register_date_to'
        ] as $key) {
            $value = Sanitizer::sanitize($input[$key] ?? '');
            if ($value !== '' && $value !== 'all') {
                $filters[$key] = $value;
            }
        }
        return $filters;
    }

    private function normalizeLeadTransferLimit($value): ?int
    {
        if ($value === null || $value === '') {
            return null;
        }
        $limit = (int)$value;
        if ($limit <= 0) {
            return null;
        }
        return min($limit, 10000);
    }

    private function buildLeadTransferWhere(string $fromUserId, array $filters): array
    {
        $where = ["p.didar_contact_id IS NOT NULL", "p.owner_didar_id = ?"];
        $params = [$fromUserId];

        if (!empty($filters['previous_owner_id'])) {
            if ($this->db->hasColumn('persons', 'previous_owner_history')) {
                $where[] = "(p.previous_owner_id = ? OR FIND_IN_SET(?, COALESCE(p.previous_owner_history, '')) > 0)";
                $params[] = $filters['previous_owner_id'];
                $params[] = $filters['previous_owner_id'];
            } else {
                $where[] = "p.previous_owner_id = ?";
                $params[] = $filters['previous_owner_id'];
            }
        }

        if (!empty($filters['sale_status'])) {
            if ($filters['sale_status'] === 'success') {
                $where[] = "p.sale_status = 1";
            } elseif ($filters['sale_status'] === 'failed') {
                $where[] = "p.sale_status = 0";
            }
        }

        if (!empty($filters['product_id'])) {
            $productId = (int)$filters['product_id'];
            $productName = $this->getProductNameById($productId);
            $or = ["EXISTS (
                SELECT 1 FROM deals d
                JOIN deal_products dp ON dp.deal_id = d.id
                WHERE d.contact_didar_id = p.didar_contact_id AND d.status = 'Won' AND dp.product_id = ?
            )"];
            $params[] = $productId;
            if ($productName !== '') {
                $or[] = "p.customer_products LIKE ?";
                $params[] = '%' . $productName . '%';
            }
            $where[] = '(' . implode(' OR ', $or) . ')';
        } elseif (!empty($filters['product_name'])) {
            $where[] = "p.customer_products LIKE ?";
            $params[] = '%' . $filters['product_name'] . '%';
        }

        if (!empty($filters['requested_service'])) {
            $where[] = "p.requested_services LIKE ?";
            $params[] = '%' . $filters['requested_service'] . '%';
        }

        if (!empty($filters['content_topic'])) {
            $where[] = "p.content_topic = ?";
            $params[] = $filters['content_topic'];
        }

        if (!empty($filters['customer_level'])) {
            $where[] = "p.customer_level = ?";
            $params[] = $filters['customer_level'];
        }

        if (!empty($filters['search'])) {
            $where[] = "(p.customer_code LIKE ? OR p.first_name LIKE ? OR p.last_name LIKE ? OR p.mobile_phone LIKE ? OR p.secondary_mobile_phone LIKE ? OR p.email LIKE ?)";
            $needle = '%' . $filters['search'] . '%';
            $params = array_merge($params, [$needle, $needle, $needle, $needle, $needle, $needle]);
        }

        if (!empty($filters['register_date_from']) && preg_match('/^\d{4}[-\/]\d{1,2}[-\/]\d{1,2}$/', $filters['register_date_from'])) {
            $where[] = "CAST(p.register_time AS CHAR) >= ?";
            $params[] = str_replace('/', '-', $filters['register_date_from']) . " 00:00:00";
        }

        if (!empty($filters['register_date_to']) && preg_match('/^\d{4}[-\/]\d{1,2}[-\/]\d{1,2}$/', $filters['register_date_to'])) {
            $where[] = "CAST(p.register_time AS CHAR) <= ?";
            $params[] = str_replace('/', '-', $filters['register_date_to']) . " 23:59:59";
        }

        return [implode(' AND ', $where), $params];
    }

    private function buildFilteredLeadTransferReport(string $fromUserId, array $filters, ?int $limit): array
    {
        $pdo = $this->db->getPdo();
        [$whereSql, $params] = $this->buildLeadTransferWhere($fromUserId, $filters);

        $countStmt = $pdo->prepare("SELECT COUNT(*) FROM persons p WHERE {$whereSql}");
        $countStmt->execute($params);
        $matchedCount = (int)$countStmt->fetchColumn();

        $sql = "SELECT p.didar_contact_id FROM persons p WHERE {$whereSql} ORDER BY p.register_time DESC, p.created_at DESC, p.didar_contact_id ASC";
        if ($limit !== null) {
            $sql .= " LIMIT " . (int)$limit;
        }
        $stmt = $pdo->prepare($sql);
        $stmt->execute($params);
        $ids = array_map(static function ($row) {
            return (string)$row['didar_contact_id'];
        }, $stmt->fetchAll(PDO::FETCH_ASSOC) ?: []);

        return [
            'counts' => [
                'persons_owner' => [
                    'label' => 'لیدهای فیلترشده',
                    'count' => count($ids),
                    'matched_count' => $matchedCount,
                    'limit' => $limit
                ]
            ],
            'details' => [
                'persons_owner' => [
                    'label' => 'لیدهای فیلترشده',
                    'id_column' => 'didar_contact_id',
                    'identifiers' => $ids
                ]
            ],
            'notes' => [
                'این حالت فقط لیدهای مطابق فیلتر را منتقل می‌کند و معاملات/فعالیت‌ها/اعلان‌ها را جابه‌جا نمی‌کند.',
                'مالک فعلی لید به مسئول قبلی و تاریخچه مالک‌ها اضافه می‌شود؛ تاریخچه قبلی حذف نمی‌شود.'
            ]
        ];
    }

    private function getProductNameById(int $productId): string
    {
        if ($productId <= 0 || !$this->tableExists('products')) {
            return '';
        }
        $pdo = $this->db->getPdo();
        $stmt = $pdo->prepare("SELECT name FROM products WHERE id = ? LIMIT 1");
        $stmt->execute([$productId]);
        return trim((string)($stmt->fetchColumn() ?: ''));
    }

    public function getTransferReport()
    {
        $this->requireAdminOrDelegated('users.admin.transfer_data');
        $userDidarId = Sanitizer::sanitize($_POST['user_didar_id'] ?? $_GET['user_didar_id'] ?? '');
        if ($userDidarId === '') {
            $this->errorResponse('شناسه دیدار کاربر الزامی است');
        }
        $report = $this->buildTransferReport($userDidarId);
        $this->successResponse($report);
    }

    public function deleteUser()
    {
        $this->requireAdminOrDelegated('users.admin.delete');

        $userId = (int)($_POST['user_id'] ?? 0);
        if ($userId <= 0) {
            $this->errorResponse('شناسه کاربر الزامی است');
        }
        if ((int)($_SESSION['user_id'] ?? 0) === $userId) {
            $this->errorResponse('حذف کاربر فعلی مجاز نیست');
        }

        $user = $this->userRepo->findById($userId);
        if (!$user) {
            $this->errorResponse('کاربر یافت نشد', 404);
        }

        $report = $this->buildTransferReport((string)$user->didar_user_id);
        $pdo = $this->db->getPdo();
        try {
            $pdo->beginTransaction();

            if ($this->tableExists('crm_support_logs') && $this->db->hasColumn('crm_support_logs', 'created_by_didar_id')) {
                $stmt = $pdo->prepare("UPDATE crm_support_logs SET created_by_didar_id = NULL WHERE created_by_didar_id = ?");
                $stmt->execute([(string)$user->didar_user_id]);
            }
            if ($this->db->hasColumn('deals', 'created_by_didar_id')) {
                $stmt = $pdo->prepare("UPDATE deals SET created_by_didar_id = NULL, created_by_name = NULL WHERE created_by_didar_id = ?");
                $stmt->execute([(string)$user->didar_user_id]);
            }

            $this->userRepo->deleteById($userId);
            $pdo->commit();
        } catch (\Throwable $e) {
            if ($pdo->inTransaction()) {
                $pdo->rollBack();
            }
            \App\Utils\Logger::logError('Failed to delete user', $e, ['user_id' => $userId, 'didar_user_id' => $user->didar_user_id]);
            $this->errorResponse('حذف کاربر با خطا مواجه شد');
        }

        $this->successResponse([
            'deleted_user' => $user->toArray(),
            'details' => $report['details'],
            'notes' => array_merge($report['notes'], ['در صورت وجود ارجاعات مالکیتی، روابط دارای Foreign Key به NULL/حذف آبشاری واگذار شدند.'])
        ], 'کاربر با موفقیت حذف شد');
    }

    private function getTransferTargets(): array
    {
        $targets = [
            ['key' => 'persons_owner', 'table' => 'persons', 'column' => 'owner_didar_id', 'label' => 'لیدها', 'id_column' => 'didar_contact_id'],
            ['key' => 'deals_owner', 'table' => 'deals', 'column' => 'owner_didar_id', 'label' => 'معاملات (مسئول)', 'id_column' => 'didar_deal_id'],
            ['key' => 'deals_created_by', 'table' => 'deals', 'column' => 'created_by_didar_id', 'label' => 'معاملات (ثبت‌کننده)', 'id_column' => 'didar_deal_id'],
            ['key' => 'activities_owner', 'table' => 'activities', 'column' => 'owner_didar_id', 'label' => 'فعالیت‌ها', 'id_column' => 'didar_activity_id'],
            ['key' => 'referrals', 'table' => 'referrals', 'column' => 'referrer_didar_id', 'label' => 'ارجاعات', 'id_column' => 'id'],
            ['key' => 'satisfactions', 'table' => 'customer_satisfactions', 'column' => 'registered_by_didar_id', 'label' => 'رضایت‌سنجی‌ها', 'id_column' => 'id'],
            ['key' => 'notifications', 'table' => 'notifications', 'column' => 'user_didar_id', 'label' => 'اعلان‌ها', 'id_column' => 'id'],
        ];

        if ($this->tableExists('crm_support_logs')) {
            $targets[] = ['key' => 'support_logs', 'table' => 'crm_support_logs', 'column' => 'created_by_didar_id', 'label' => 'پشتیبانی', 'id_column' => 'id'];
        }

        return $targets;
    }

    private function buildTransferReport(string $fromUserId): array
    {
        $pdo = $this->db->getPdo();
        $counts = [];
        $details = [];

        foreach ($this->getTransferTargets() as $item) {
            if (!$this->db->hasColumn($item['table'], $item['column'])) {
                continue;
            }
            $idColumn = $item['id_column'];
            $stmt = $pdo->prepare("SELECT {$idColumn} FROM {$item['table']} WHERE {$item['column']} = ? ORDER BY {$idColumn} ASC");
            $stmt->execute([$fromUserId]);
            $ids = array_map(static function ($row) use ($idColumn) {
                return (string)$row[$idColumn];
            }, $stmt->fetchAll(PDO::FETCH_ASSOC));

            $counts[$item['key']] = [
                'label' => $item['label'],
                'count' => count($ids)
            ];
            $details[$item['key']] = [
                'label' => $item['label'],
                'id_column' => $idColumn,
                'identifiers' => $ids
            ];
        }

        return [
            'counts' => $counts,
            'details' => $details,
            'notes' => [
                'پرداخت‌ها جدول مالکیت مستقیم کاربر ندارند و با انتقال مالک معامله، پرداخت‌ها به‌صورت غیرمستقیم تحت کاربر جدید قرار می‌گیرند.',
                'برای لیدها، مالک قبلی حذف نمی‌شود و زنجیره مالکیت در تاریخچه مالک نگه‌داری می‌شود.',
                'virtual_stages مالک کاربر ندارند و انتقال مستقیم روی آن‌ها لازم نیست.'
            ]
        ];
    }

    private function tableExists(string $table): bool
    {
        try {
            $pdo = $this->db->getPdo();
            $stmt = $pdo->prepare("SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ?");
            $stmt->execute([$table]);
            return (int)$stmt->fetchColumn() > 0;
        } catch (\Throwable $e) {
            return false;
        }
    }

    public function changePassword()
    {
        $userId = intval($_POST['user_id'] ?? 0);
        $currentPassword = $_POST['current_password'] ?? '';
        $newPassword = $_POST['new_password'] ?? '';
        $confirmPassword = $_POST['confirm_password'] ?? '';
        
        if (empty($userId) || empty($newPassword)) {
            $this->errorResponse('شناسه کاربر و رمز عبور جدید الزامی است');
        }
        
        if ($newPassword !== $confirmPassword) {
            $this->errorResponse('رمز عبور جدید و تأیید آن مطابقت ندارند');
        }
        
        if (strlen($newPassword) < 6) {
            $this->errorResponse('رمز عبور باید حداقل 6 کاراکتر باشد');
        }
        
        $user = $this->userRepo->findById($userId);
        if (!$user) {
            $this->errorResponse('کاربر یافت نشد');
        }
        
        $currentUserId = (int)($_SESSION['user_id'] ?? 0);
        $isOwnPasswordChange = ($userId === $currentUserId);

        if ($isOwnPasswordChange) {
            if (empty($currentPassword) || empty($user->password) || !password_verify($currentPassword, $user->password)) {
                $this->errorResponse('رمز عبور فعلی اشتباه است');
            }
        } elseif (!$this->authService->isAdmin() && !$this->hasDelegatedCapability('users.admin.passwords.change')) {
            $this->errorResponse('دسترسی محدود به مدیر سیستم');
        }
        
        $hashedPassword = password_hash($newPassword, PASSWORD_DEFAULT);
        $this->userRepo->updatePassword($userId, $hashedPassword);
        
        $this->successResponse([], 'رمز عبور با موفقیت تغییر یافت');
    }

    public function updateRole()
    {
        $this->requireAdminOrDelegated('users.admin.roles.edit');
        
        $userId = intval($_POST['user_id'] ?? 0);
        $role = Sanitizer::sanitize($_POST['role'] ?? '');
        
        if (empty($userId) || empty($role)) {
            $this->errorResponse('شناسه کاربر و نقش الزامی است');
        }
        
        if (!$this->isValidRoleKey($role)) {
            $this->errorResponse('نقش نامعتبر است');
        }
        
        $this->userRepo->updateRole($userId, $role);
        $this->successResponse([], 'نقش کاربر با موفقیت تغییر یافت');
    }

    /**
     * Get Didar users list for lead owner selection
     * Requires admin or CRM specialist role
     * Falls back to local database if Didar API fails
     */
    public function getDidarUsers()
    {
        $resourceKey = Sanitizer::sanitize($_REQUEST['resource_key'] ?? 'leads');
        $allowed = $this->authService->isAdminOrCrmSpecialist();
        if (!$allowed) {
            global $app;
            if (isset($app->services->rbac) && $app->services->rbac) {
                $allowed = true;
            }
        }

        if (!$allowed) {
            $this->errorResponse('دسترسی محدود به گزینه‌های مسئول');
        }

        if (!$this->db) {
            // Try to get from global app
            global $app;
            if (!isset($app)) {
                $app = $GLOBALS['app'] ?? null;
            }
            if ($app) {
                $this->db = $this->db ?? $app->db;
                $this->didarApi = $this->didarApi ?? $app->services->didarApi;
            }
        }

        if (!$this->db) {
            $this->errorResponse('خطا در دسترسی به دیتابیس');
        }

        $pdo = $this->db->getPdo();
        // فقط از دیتابیس محلی و کاربران فعال بخوانیم (بدون همگام‌سازی دیدار)
        $hasDisplayName = $this->db->hasColumn('users', 'display_name');
        $fields = $hasDisplayName ? "id, didar_user_id, display_name, email, is_active" : "id, didar_user_id, first_name, last_name, email, is_active";
        
        $stmtLocal = $pdo->prepare("SELECT $fields FROM users WHERE is_active = 1");
        $stmtLocal->execute();
        $rows = $stmtLocal->fetchAll(PDO::FETCH_ASSOC);

        $allowedDidarIds = null;
        global $app;
        if (isset($app->services->rbac) && $app->services->rbac && !$this->authService->isAdminOrCrmSpecialist()) {
            $scope = (array)$app->services->rbac->getDataScope($resourceKey);
            $scopeType = trim((string)($scope['scope_type'] ?? 'none'));
            if ($scopeType !== 'all') {
                $allowedDidarIds = $app->services->rbac->allowedDidarIdsForScope($resourceKey);
            }
        }

        $usersLocal = [];
        foreach ($rows as $u) {
            $didarUserId = (string)($u['didar_user_id'] ?? '');
            if (is_array($allowedDidarIds) && !in_array($didarUserId, $allowedDidarIds, true)) {
                continue;
            }
            $displayName = $hasDisplayName
                ? ($u['display_name'] ?? '')
                : trim(($u['first_name'] ?? '') . ' ' . ($u['last_name'] ?? ''));
            $usersLocal[] = [
                'id' => $u['id'],
                'owner_id' => $didarUserId,
                'display_name' => $displayName,
                'email' => $u['email'] ?? '',
                'is_active' => 1
            ];
        }
        
        $this->successResponse([
            'users' => $usersLocal,
            'source' => 'local_only'
        ]);
        return;

        // legacy code below (will not run because of return)
        $users = [];
        $source = 'local'; // default source
        $totalFromDidar = 0;
        $skippedNoUserId = 0;
        $autoSynced = 0;
        $alreadyExists = 0;
        
        \App\Utils\Logger::logInfo("Fetching Didar users", ['role' => $_SESSION['role'] ?? 'unknown']);
        
        // Try to fetch from Didar API first
        $didarRes = null;
        if ($this->didarApi) {
            try {
                $didarRes = $this->didarApi->call('/User/List', 'POST');
            } catch (\Exception $e) {
                \App\Utils\Logger::logWarning("Didar API call failed, falling back to local database", ['error' => $e->getMessage()]);
                $didarRes = null;
            }
        }
        
        $hasDisplayName = $this->db->hasColumn('users', 'display_name');
        
        // If Didar API returned data, process it
        if ($didarRes && !isset($didarRes['error']) && isset($didarRes['Response']) && is_array($didarRes['Response'])) {
            $source = 'didar';
            $totalFromDidar = count($didarRes['Response']);
            \App\Utils\Logger::logInfo("Received users from Didar", ['count' => $totalFromDidar]);
            
            foreach ($didarRes['Response'] as $u) {
                // بر اساس مستندات Didar: استفاده از Id به عنوان اولویت اول
                // UserId ممکن است 00000000-0000-0000-0000-000000000000 باشد
                $didarUserId = $u['Id'] ?? $u['UserId'] ?? null;
                
                // اگر UserId معتبر نیست (همه صفر) از Id استفاده کن
                if ($didarUserId === '00000000-0000-0000-0000-000000000000' || empty($didarUserId)) {
                    $didarUserId = $u['Id'] ?? null;
                }
                
                if (!$didarUserId) {
                    $skippedNoUserId++;
                    \App\Utils\Logger::logWarning("Skipping user without Id/UserId", ['user_data' => $u]);
                    continue;
                }
                
                // Check if user exists in local users table
                if ($hasDisplayName) {
                    $stmt = $pdo->prepare("SELECT didar_user_id, display_name, is_active FROM users WHERE didar_user_id = ? LIMIT 1");
                } else {
                    $stmt = $pdo->prepare("SELECT didar_user_id, is_active FROM users WHERE didar_user_id = ? LIMIT 1");
                }
                $stmt->execute([$didarUserId]);
                $localUser = $stmt->fetch(PDO::FETCH_ASSOC);
                
                // If user doesn't exist, add it to users table (auto-sync)
                if (!$localUser) {
                    try {
                        $isActive = (isset($u['IsDisabled']) && $u['IsDisabled']) ? 0 : 1;
                        
                        if ($hasDisplayName) {
                            $pdo->prepare("INSERT INTO users (didar_user_id, email, first_name, last_name, display_name, role, is_active, last_sync) 
                                VALUES (?, ?, ?, ?, ?, 'agent', ?, NOW())
                                ON DUPLICATE KEY UPDATE 
                                    email = VALUES(email),
                                    first_name = VALUES(first_name),
                                    last_name = VALUES(last_name),
                                    display_name = VALUES(display_name),
                                    is_active = VALUES(is_active),
                                    last_sync = NOW()")
                                ->execute([
                                    $didarUserId,
                                    $u['UserName'] ?? '',
                                    $u['FirstName'] ?? '',
                                    $u['LastName'] ?? '',
                                    $u['DisplayName'] ?? '',
                                    $isActive
                                ]);
                        } else {
                            $pdo->prepare("INSERT INTO users (didar_user_id, email, first_name, last_name, role, is_active, last_sync) 
                                VALUES (?, ?, ?, ?, 'agent', ?, NOW())
                                ON DUPLICATE KEY UPDATE 
                                    email = VALUES(email),
                                    first_name = VALUES(first_name),
                                    last_name = VALUES(last_name),
                                    is_active = VALUES(is_active),
                                    last_sync = NOW()")
                                ->execute([
                                    $didarUserId,
                                    $u['UserName'] ?? '',
                                    $u['FirstName'] ?? '',
                                    $u['LastName'] ?? '',
                                    $isActive
                                ]);
                        }
                        
                        // Fetch the newly added user
                        if ($hasDisplayName) {
                            $stmt = $pdo->prepare("SELECT didar_user_id, display_name, is_active FROM users WHERE didar_user_id = ? LIMIT 1");
                        } else {
                            $stmt = $pdo->prepare("SELECT didar_user_id, is_active FROM users WHERE didar_user_id = ? LIMIT 1");
                        }
                        $stmt->execute([$didarUserId]);
                        $localUser = $stmt->fetch(PDO::FETCH_ASSOC);
                        $autoSynced++;
                        \App\Utils\Logger::logInfo("Auto-synced user from Didar", [
                            'user_id' => $didarUserId, 
                            'display_name' => $u['DisplayName'] ?? '',
                            'is_active' => $isActive
                        ]);
                    } catch (\Exception $e) {
                        \App\Utils\Logger::logError("Failed to auto-sync user", $e, ['user_id' => $didarUserId]);
                        continue;
                    }
                } else {
                    $alreadyExists++;
                }
                
                // نمایش همه کاربران (فعال و غیرفعال)
                // اگر $localUser null است، دوباره fetch کن
                if (!$localUser) {
                    if ($hasDisplayName) {
                        $stmt = $pdo->prepare("SELECT didar_user_id, display_name, is_active FROM users WHERE didar_user_id = ? LIMIT 1");
                    } else {
                        $stmt = $pdo->prepare("SELECT didar_user_id, is_active FROM users WHERE didar_user_id = ? LIMIT 1");
                    }
                    $stmt->execute([$didarUserId]);
                    $localUser = $stmt->fetch(PDO::FETCH_ASSOC);
                    
                    if (!$localUser) {
                        \App\Utils\Logger::logWarning("User still not found after re-fetch", [
                            'didar_user_id' => $didarUserId,
                            'display_name' => $u['DisplayName'] ?? ''
                        ]);
                    }
                }
                
                // همیشه کاربر را اضافه کن (حتی اگر $localUser null باشد، از داده‌های Didar استفاده کن)
                if (!empty($didarUserId)) {
                    $displayName = '';
                    $isActive = 1;
                    
                    if ($localUser) {
                        $displayName = $localUser['display_name'] ?? '';
                        $isActive = $localUser['is_active'] ?? 1;
                    }
                    
                    // اگر display_name خالی است، از Didar استفاده کن
                    if (empty($displayName)) {
                        $displayName = $u['DisplayName'] ?? (($u['FirstName'] ?? '') . ' ' . ($u['LastName'] ?? ''));
                    }
                    
                    // اگر هنوز خالی است، از UserName استفاده کن
                    if (empty($displayName)) {
                        $displayName = $u['UserName'] ?? $didarUserId;
                    }
                    
                    // برای OwnerId در contact/save، باید از UserId استفاده کنیم نه Id
                    // اما اگر UserId معتبر نیست (همه صفر)، از Id استفاده می‌کنیم
                    $ownerId = $u['UserId'] ?? $didarUserId;
                    if ($ownerId === '00000000-0000-0000-0000-000000000000' || empty($ownerId)) {
                        $ownerId = $didarUserId; // Use Id as fallback
                    }
                    
                    $users[] = [
                        'id' => $didarUserId, // برای ذخیره در دیتابیس
                        'owner_id' => $ownerId, // برای ارسال به Didar API (UserId)
                        'display_name' => trim($displayName),
                        'email' => $u['UserName'] ?? '',
                        'role' => $u['Role'] ?? '',
                        'is_active' => $isActive
                    ];
                }
            }
            
            \App\Utils\Logger::logInfo("Didar users processing complete", [
                'total_from_didar' => $totalFromDidar,
                'returned_to_client' => count($users),
                'auto_synced' => $autoSynced,
                'already_exists' => $alreadyExists,
                'skipped_no_userid' => $skippedNoUserId
            ]);
        } else {
            // Fallback: Get users from local database
            \App\Utils\Logger::logInfo("Falling back to local database for users", [
                'didar_error' => $didarRes['error'] ?? null,
                'has_response' => isset($didarRes['Response'])
            ]);
            
            try {
                if ($hasDisplayName) {
                    $stmt = $pdo->query("SELECT didar_user_id, display_name, email, is_active FROM users WHERE didar_user_id IS NOT NULL AND didar_user_id != '' ORDER BY display_name");
                } else {
                    $stmt = $pdo->query("SELECT didar_user_id, first_name, last_name, email, is_active FROM users WHERE didar_user_id IS NOT NULL AND didar_user_id != '' ORDER BY first_name, last_name");
                }
                
                $localUsers = $stmt->fetchAll(PDO::FETCH_ASSOC);
                
                foreach ($localUsers as $localUser) {
                    $displayName = $localUser['display_name'] ?? trim(($localUser['first_name'] ?? '') . ' ' . ($localUser['last_name'] ?? ''));
                    
                    if (!empty($displayName) || !empty($localUser['email'])) {
                        $users[] = [
                            'id' => $localUser['didar_user_id'],
                            'display_name' => $displayName ?: $localUser['email'],
                            'email' => $localUser['email'] ?? '',
                            'role' => '',
                            'is_active' => $localUser['is_active'] ?? 1
                        ];
                    }
                }
                
                \App\Utils\Logger::logInfo("Loaded users from local database", ['count' => count($users)]);
            } catch (\Exception $e) {
                \App\Utils\Logger::logError("Failed to load users from local database", $e);
            }
        }
        
        $this->successResponse([
            'users' => $users,
            'debug' => [
                'source' => $source,
                'total_from_didar' => $totalFromDidar,
                'returned_count' => count($users),
                'auto_synced' => $autoSynced,
                'skipped_no_userid' => $skippedNoUserId
            ]
        ]);
    }
}
