<?php
namespace App\Controllers;

use App\Repositories\PersonRepository;
use App\Repositories\DealRepository;
use App\Repositories\ActivityRepository;
use App\Repositories\LookupRepository;
use App\Services\AuthService;

class DashboardController extends ApiController
{
    private $personRepo;
    private $dealRepo;
    private $activityRepo;
    private $lookupRepo;
    private $authService;

    private function canRbac(string $capabilityKey): bool
    {
        global $app;
        return isset($app->services->rbac) && $app->services->rbac && $app->services->rbac->can($capabilityKey);
    }

    private function getRbacScopeForResource(string $resourceKey): ?array
    {
        global $app;
        if (!isset($app->services->rbac) || !$app->services->rbac) {
            return null;
        }
        $scope = (array)$app->services->rbac->getDataScope($resourceKey);
        $scopeType = trim((string)($scope['scope_type'] ?? ''));
        if ($resourceKey === 'dashboard' && ($scopeType === '' || ($scopeType === 'self' && empty($scope['selected_user_ids'])))) {
            // Dashboard often follows leads visibility if a dedicated dashboard scope was not configured yet.
            $fallback = (array)$app->services->rbac->getDataScope('leads');
            if (!empty($fallback)) {
                return $fallback;
            }
        }
        return $scope;
    }

    private function mapSelectedUserIdsToDidarIds(array $selectedUserIds): array
    {
        global $app;
        if (!isset($app->repositories->user) || !$app->repositories->user) {
            return [];
        }
        $didarIds = [];
        foreach ($selectedUserIds as $uid) {
            $userId = (int)$uid;
            if ($userId <= 0) continue;
            try {
                $user = $app->repositories->user->findById($userId);
                $didar = trim((string)($user->didar_user_id ?? ''));
                if ($didar !== '') $didarIds[$didar] = true;
            } catch (\Throwable $e) {}
        }
        return array_keys($didarIds);
    }

    private function applyDashboardOwnerScope(array &$filters, string $requestedOwnerDidarId, string $selfDidarId): void
    {
        global $app;
        if (isset($app->services->rbac) && $app->services->rbac) {
            $filters = $app->services->rbac->applyOwnerScope($filters, 'dashboard', $requestedOwnerDidarId);
        }
    }

    public function __construct(
        PersonRepository $personRepo,
        DealRepository $dealRepo,
        ActivityRepository $activityRepo,
        LookupRepository $lookupRepo,
        AuthService $authService
    ) {
        $this->personRepo = $personRepo;
        $this->dealRepo = $dealRepo;
        $this->activityRepo = $activityRepo;
        $this->lookupRepo = $lookupRepo;
        $this->authService = $authService;
    }

    private function normalizePipelineStageComparable(string $value): string
    {
        $value = trim($value);
        if ($value === '') {
            return '';
        }

        return preg_replace('/\s+/u', ' ', $value) ?? $value;
    }

    private function getPipelineStageLookupSummary(): array
    {
        $summary = [
            'active' => [],
            'inactive' => [],
        ];

        foreach ($this->lookupRepo->getItemsByGroupCode('pipeline_stages', true) as $item) {
            $value = trim((string)($item['value'] ?? $item['title'] ?? ''));
            if ($value === '') {
                continue;
            }

            $key = $this->normalizePipelineStageComparable($value);
            $record = [
                'value' => $value,
                'title' => trim((string)($item['title'] ?? $value)) ?: $value,
            ];
            $isActive = (int)($item['is_active'] ?? 1) === 1 && (int)($item['is_visible'] ?? 1) === 1;
            $didarUserId = trim((string)($_SESSION['didar_id'] ?? ''));
            if ($isActive && $didarUserId !== '' && $this->lookupRepo->isLookupItemDisabledForDidarUser((array)$item, $didarUserId)) {
                $isActive = false;
            }

            if ($isActive) {
                $summary['active'][$key] = $record;
                unset($summary['inactive'][$key]);
                continue;
            }

            if (!isset($summary['active'][$key])) {
                $summary['inactive'][$key] = $record;
            }
        }

        return $summary;
    }

    public function getStats()
    {
        if (!$this->canRbac('dashboard.view')) {
            $this->errorResponse('دسترسی محدود - شما مجاز به مشاهده داشبورد نیستید', 403);
        }
        $isAdmin = $this->authService->isAdmin();
        $isAdminOrCrm = $this->authService->isAdminOrCrmSpecialist();
        $didarId = $_SESSION['didar_id'] ?? '';
        
        $ownerFilter = $_POST['owner_didar_id'] ?? '';
        $statusFilter = $_POST['status'] ?? 'all';

        $stats = [];
        
        // Get total leads count (without pagination)
        $filters = [];
        if ($isAdminOrCrm && !empty($ownerFilter)) {
            $filters['owner_didar_id'] = $ownerFilter;
        } elseif (!$isAdminOrCrm && !empty($didarId)) {
            $filters['owner_didar_id'] = $didarId;
        }
        $this->applyDashboardOwnerScope($filters, (string)$ownerFilter, (string)$didarId);
        
        // PERF (phase 2): one conditional-aggregate scan of `persons` for total + won + fail
        // instead of three separate COUNT(*) scans (getLeadsCount + two sale_status counts).
        // Verified equivalent against the prod (17) dataset for both admin and owner scope.
        $db = $this->personRepo->getDb();
        $pdo = $db->getPdo();
        $whereClause = "didar_contact_id IS NOT NULL";
        $params = [];
        if (!empty($filters['owner_didar_ids']) && is_array($filters['owner_didar_ids'])) {
            $ids = array_values(array_filter(array_map('strval', $filters['owner_didar_ids'])));
            $whereClause .= " AND owner_didar_id IN (" . implode(',', array_fill(0, count($ids), '?')) . ")";
            $params = array_merge($params, $ids);
        } elseif (!empty($filters['owner_didar_id'])) {
            $whereClause .= " AND owner_didar_id = ?";
            $params[] = $filters['owner_didar_id'];
        }
        $stmt = $pdo->prepare("SELECT COUNT(*) AS total, SUM(sale_status = 1) AS won, SUM(sale_status = 0) AS fail FROM persons WHERE $whereClause");
        $stmt->execute($params);
        $leadAgg = $stmt->fetch(\PDO::FETCH_ASSOC) ?: [];
        $stats['total_leads'] = (int)($leadAgg['total'] ?? 0);
        $stats['successful_leads'] = (int)($leadAgg['won'] ?? 0);
        $stats['failed_leads'] = (int)($leadAgg['fail'] ?? 0);

        // Deals pipeline stats (NO LIMIT; fixes "always 100" bug)
        $dealFilters = $filters;
        if ($statusFilter !== 'all') {
            $dealFilters['status'] = $statusFilter;
        }

        // Kariz stage cards represent current open deals only. Closed Won/Lost deals
        // can keep their historical pipeline_stage but should not keep the live stage full.
        $currentDealFilters = array_merge($filters, ['legacy' => '0', 'exclude_parked' => true, 'status' => 'Pending']);
        $parkedDealFilters = array_merge($filters, ['legacy' => '0', 'pipeline_bucket' => 'parked', 'status' => 'Pending']);
        $stats['total_deals'] = $this->dealRepo->countAll($dealFilters); 
        $stats['deals_by_stage'] = $this->dealRepo->getStageCounts($currentDealFilters);
        $stats['parked_deals_by_stage'] = $this->dealRepo->getStageCounts(array_merge($parkedDealFilters, ['stage_count_field' => 'parked_from_stage']));

        $pipelineLookupSummary = $this->getPipelineStageLookupSummary();
        $activeStages = array_values(array_map(static function (array $item) {
            return $item['value'];
        }, $pipelineLookupSummary['active']));

        $ongoingCount = 0;
        foreach ($activeStages as $stage) {
            if (isset($stats['deals_by_stage'][$stage])) {
                $ongoingCount += $stats['deals_by_stage'][$stage];
            }
        }
        $stats['ongoing_deals'] = $ongoingCount;

        $stats['inactive_stage_deals'] = [];
        $stats['inactive_stage_deals_total'] = 0;
        foreach ($pipelineLookupSummary['inactive'] as $item) {
            $stageValue = $item['value'];
            $count = (int)($stats['deals_by_stage'][$stageValue] ?? 0);
            if ($count <= 0) {
                continue;
            }

            $stats['inactive_stage_deals'][] = [
                'value' => $stageValue,
                'title' => $item['title'],
                'count' => $count,
            ];
            $stats['inactive_stage_deals_total'] += $count;
        }

        $stats['parked_stage_deals'] = [];
        $stats['parked_stage_deals_total'] = 0;
        foreach (($stats['parked_deals_by_stage'] ?? []) as $stageValue => $count) {
            $normalizedStage = trim((string)$stageValue);
            if ($normalizedStage === '' || $count <= 0) {
                continue;
            }
            $stats['parked_stage_deals'][] = [
                'value' => $normalizedStage,
                'title' => $normalizedStage,
                'count' => (int)$count,
            ];
            $stats['parked_stage_deals_total'] += (int)$count;
        }
        $stats['parked_by_user'] = $this->dealRepo->getParkedByUserSummary($parkedDealFilters);

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