<?php

namespace Espo\Modules\SmartAssistant\Services;

use Espo\Core\Acl;
use Espo\ORM\EntityManager;

class AlertCalculator
{
    private EntityManager $entityManager;
    private Acl $acl;

    private const CLOSED_STATUSES = ['ClosedSettlement', 'ClosedJudgment', 'Closed', 'Rejected'];

    public function __construct(EntityManager $entityManager, Acl $acl)
    {
        $this->entityManager = $entityManager;
        $this->acl = $acl;
    }

    public function calculateAlerts(array $thresholds = []): array
    {
        $inactivityWarningDays = $thresholds['inactivityWarningDays'] ?? 14;
        $inactivityCriticalDays = $thresholds['inactivityCriticalDays'] ?? 30;
        $upcomingHearingDays = $thresholds['upcomingHearingDays'] ?? 7;

        $alerts = [];
        $alerts = array_merge($alerts, $this->findInactiveCases($inactivityWarningDays, $inactivityCriticalDays));
        $alerts = array_merge($alerts, $this->findOverdueTasks());
        $alerts = array_merge($alerts, $this->findUpcomingHearingsWithoutPrep($upcomingHearingDays));
        $alerts = array_merge($alerts, $this->findUnassignedNewCases());
        $alerts = array_merge($alerts, $this->findUpcomingTasks());

        $severityOrder = ['critical' => 0, 'warning' => 1, 'info' => 2];
        usort($alerts, fn($a, $b) => ($severityOrder[$a['severity']] ?? 3) <=> ($severityOrder[$b['severity']] ?? 3));

        return $alerts;
    }

    public function getSummary(): array
    {
        $today = date('Y-m-d');
        $weekEnd = date('Y-m-d', strtotime('+7 days'));

        $totalOpenCases = $this->entityManager->getRDBRepository('Case')
            ->where(['status!=' => self::CLOSED_STATUSES, 'deleted' => false])->count();

        $totalOverdueTasks = $this->entityManager->getRDBRepository('Task')
            ->where(['status!=' => ['Completed', 'Canceled', 'Deferred'], 'dateEnd<' => $today, 'dateEnd!=' => null, 'deleted' => false, 'parentType' => 'Case'])->count();

        $upcomingHearings = $this->entityManager->getRDBRepository('Case')
            ->where(['cNextHearing>=' => $today, 'cNextHearing<=' => $weekEnd, 'status!=' => self::CLOSED_STATUSES, 'deleted' => false])->count();

        $alerts = $this->calculateAlerts();
        $criticalCount = count(array_filter($alerts, fn($a) => $a['severity'] === 'critical'));
        $warningCount = count(array_filter($alerts, fn($a) => $a['severity'] === 'warning'));

        return [
            'totalOpenCases' => $totalOpenCases,
            'totalOverdueTasks' => $totalOverdueTasks,
            'upcomingHearings7d' => $upcomingHearings,
            'casesNeedingAttention' => $criticalCount + $warningCount,
            'criticalAlerts' => $criticalCount,
            'warningAlerts' => $warningCount,
        ];
    }

    private function findInactiveCases(int $warningDays, int $criticalDays): array
    {
        $alerts = [];
        $now = new \DateTime();
        $warningThreshold = (new \DateTime())->modify("-{$warningDays} days")->format('Y-m-d H:i:s');
        $criticalThreshold = (new \DateTime())->modify("-{$criticalDays} days")->format('Y-m-d H:i:s');

        $cases = $this->entityManager->getRDBRepository('Case')
            ->select(['id', 'name', 'status', 'assignedUserName', 'cLastActivityAt', 'createdAt'])
            ->where([
                'status!=' => self::CLOSED_STATUSES, 'deleted' => false,
                'OR' => [
                    ['cLastActivityAt<' => $warningThreshold, 'cLastActivityAt!=' => null],
                    ['cLastActivityAt' => null, 'createdAt<' => $warningThreshold],
                ],
            ])->order('cLastActivityAt', 'ASC')->limit(0, 50)->find();

        foreach ($cases as $case) {
            $lastActivity = $case->get('cLastActivityAt') ?? $case->get('createdAt');
            if (!$lastActivity) continue;
            $daysSince = $now->diff(new \DateTime($lastActivity))->days;
            $severity = ($lastActivity < $criticalThreshold) ? 'critical' : 'warning';

            $alerts[] = [
                'type' => 'inactive_case', 'severity' => $severity,
                'caseId' => $case->get('id'), 'caseName' => $case->get('name'),
                'assignedUser' => $case->get('assignedUserName'),
                'daysSinceActivity' => $daysSince,
                'message' => $case->get('name') . ' - ' . $daysSince . ' ימים ללא פעילות',
            ];
        }
        return $alerts;
    }

    private function findOverdueTasks(): array
    {
        $alerts = [];
        $today = date('Y-m-d');

        $tasks = $this->entityManager->getRDBRepository('Task')
            ->select(['id', 'name', 'dateEnd', 'status', 'parentId', 'parentType', 'parentName', 'assignedUserName'])
            ->where(['status!=' => ['Completed', 'Canceled', 'Deferred'], 'dateEnd<' => $today, 'dateEnd!=' => null, 'deleted' => false, 'parentType' => 'Case'])
            ->order('dateEnd', 'ASC')->limit(0, 50)->find();

        foreach ($tasks as $task) {
            $daysOverdue = (new \DateTime())->diff(new \DateTime($task->get('dateEnd')))->days;
            $alerts[] = [
                'type' => 'overdue_task', 'severity' => 'critical',
                'taskId' => $task->get('id'), 'taskName' => $task->get('name'),
                'caseId' => $task->get('parentId'), 'caseName' => $task->get('parentName'),
                'assignedUser' => $task->get('assignedUserName'),
                'daysOverdue' => $daysOverdue,
                'message' => $task->get('parentName') . ' - משימה "' . $task->get('name') . '" באיחור ' . $daysOverdue . ' ימים',
            ];
        }
        return $alerts;
    }

    private function findUpcomingHearingsWithoutPrep(int $hearingDays): array
    {
        $alerts = [];
        $today = date('Y-m-d');
        $threshold = date('Y-m-d', strtotime("+{$hearingDays} days"));
        $recentActivityThreshold = date('Y-m-d H:i:s', strtotime('-3 days'));
        $recentTaskThreshold = date('Y-m-d H:i:s', strtotime('-7 days'));

        $cases = $this->entityManager->getRDBRepository('Case')
            ->select(['id', 'name', 'cNextHearing', 'assignedUserName', 'cLastActivityAt'])
            ->where(['cNextHearing>=' => $today, 'cNextHearing<=' => $threshold, 'status!=' => self::CLOSED_STATUSES, 'deleted' => false])
            ->order('cNextHearing', 'ASC')->find();

        foreach ($cases as $case) {
            $lastActivity = $case->get('cLastActivityAt');
            if ($lastActivity && $lastActivity >= $recentActivityThreshold) continue;

            $openTaskCount = $this->entityManager->getRDBRepository('Task')
                ->where(['parentId' => $case->get('id'), 'parentType' => 'Case', 'status!=' => ['Completed', 'Canceled', 'Deferred'], 'deleted' => false])->count();
            if ($openTaskCount > 0) continue;

            $recentCompleted = $this->entityManager->getRDBRepository('Task')
                ->where(['parentId' => $case->get('id'), 'parentType' => 'Case', 'status' => 'Completed', 'modifiedAt>=' => $recentTaskThreshold, 'deleted' => false])->count();
            if ($recentCompleted > 0) continue;

            $daysUntil = (new \DateTime())->diff(new \DateTime($case->get('cNextHearing')))->days;
            $severity = ($daysUntil <= 1) ? 'critical' : 'warning';

            $alerts[] = [
                'type' => 'hearing_no_prep', 'severity' => $severity,
                'caseId' => $case->get('id'), 'caseName' => $case->get('name'),
                'assignedUser' => $case->get('assignedUserName'),
                'hearingDate' => $case->get('cNextHearing'), 'daysUntil' => $daysUntil,
                'message' => $case->get('name') . ' - דיון בעוד ' . $daysUntil . ' ימים, אין משימת הכנה',
            ];
        }
        return $alerts;
    }

    private function findUnassignedNewCases(): array
    {
        $alerts = [];
        $threshold = date('Y-m-d H:i:s', strtotime('-3 days'));

        $cases = $this->entityManager->getRDBRepository('Case')
            ->select(['id', 'name', 'createdAt'])->where(['status' => 'New', 'createdAt<' => $threshold, 'deleted' => false])
            ->order('createdAt', 'ASC')->limit(0, 20)->find();

        foreach ($cases as $case) {
            $daysSince = (new \DateTime())->diff(new \DateTime($case->get('createdAt')))->days;
            $alerts[] = [
                'type' => 'unassigned_case', 'severity' => 'warning',
                'caseId' => $case->get('id'), 'caseName' => $case->get('name'),
                'daysSinceCreated' => $daysSince,
                'message' => $case->get('name') . ' - תיק חדש לא שובץ (' . $daysSince . ' ימים)',
            ];
        }
        return $alerts;
    }

    private function findUpcomingTasks(): array
    {
        $alerts = [];
        $today = date('Y-m-d');
        $threshold = date('Y-m-d', strtotime('+3 days'));

        $tasks = $this->entityManager->getRDBRepository('Task')
            ->select(['id', 'name', 'dateEnd', 'parentId', 'parentType', 'parentName', 'assignedUserName'])
            ->where(['status!=' => ['Completed', 'Canceled', 'Deferred'], 'dateEnd>=' => $today, 'dateEnd<=' => $threshold, 'deleted' => false, 'parentType' => 'Case'])
            ->order('dateEnd', 'ASC')->limit(0, 30)->find();

        foreach ($tasks as $task) {
            $daysUntil = (new \DateTime())->diff(new \DateTime($task->get('dateEnd')))->days;
            $alerts[] = [
                'type' => 'upcoming_task', 'severity' => 'info',
                'taskId' => $task->get('id'), 'taskName' => $task->get('name'),
                'caseId' => $task->get('parentId'), 'caseName' => $task->get('parentName'),
                'assignedUser' => $task->get('assignedUserName'),
                'daysUntil' => $daysUntil,
                'message' => $task->get('parentName') . ' - משימה "' . $task->get('name') . '" בעוד ' . $daysUntil . ' ימים',
            ];
        }
        return $alerts;
    }

    public function getCasesByStatus(): array
    {
        $result = [];
        $statuses = ['New', 'Assigned', 'Pending', 'PendingHearing', 'PendingDecision', 'PendingResponse', 'Negotiation', 'Suspended', 'ClosedSettlement', 'ClosedJudgment', 'Closed', 'Rejected'];

        foreach ($statuses as $status) {
            $count = $this->entityManager->getRDBRepository('Case')->where(['status' => $status, 'deleted' => false])->count();
            if ($count > 0) $result[$status] = $count;
        }
        return $result;
    }

    public function getWorkloadByUser(): array
    {
        $userCounts = [];
        $cases = $this->entityManager->getRDBRepository('Case')
            ->select(['assignedUserId', 'assignedUserName'])
            ->where(['status!=' => self::CLOSED_STATUSES, 'deleted' => false, 'assignedUserId!=' => null])->find();

        foreach ($cases as $case) {
            $uid = $case->get('assignedUserId');
            if (!isset($userCounts[$uid])) {
                $userCounts[$uid] = ['userId' => $uid, 'userName' => $case->get('assignedUserName'), 'openCases' => 0, 'openTasks' => 0];
            }
            $userCounts[$uid]['openCases']++;
        }

        foreach (array_keys($userCounts) as $uid) {
            $userCounts[$uid]['openTasks'] = $this->entityManager->getRDBRepository('Task')
                ->where(['assignedUserId' => $uid, 'status!=' => ['Completed', 'Canceled', 'Deferred'], 'deleted' => false, 'parentType' => 'Case'])->count();
        }

        return array_values($userCounts);
    }

    public function getOpenCaseItems(int $limit = 30): array
    {
        $items = [];
        $cases = $this->entityManager->getRDBRepository('Case')
            ->select(['id', 'name', 'status', 'assignedUserName', 'cLastActivityAt', 'createdAt'])
            ->where(['status!=' => self::CLOSED_STATUSES, 'deleted' => false])
            ->order('createdAt', 'DESC')
            ->limit(0, $limit)
            ->find();

        $statusLabels = [
            'New' => 'חדש', 'Assigned' => 'שובץ', 'Pending' => 'ממתין',
            'PendingHearing' => 'ממתין לדיון', 'PendingDecision' => 'ממתין להחלטה',
            'PendingResponse' => 'ממתין לתגובה', 'Negotiation' => 'משא ומתן', 'Suspended' => 'מושהה',
        ];

        foreach ($cases as $case) {
            $status = $case->get('status');
            $label = $statusLabels[$status] ?? $status;
            $assigned = $case->get('assignedUserName');

            $items[] = [
                'type' => 'open_case',
                'severity' => 'info',
                'caseId' => $case->get('id'),
                'caseName' => $case->get('name'),
                'message' => $case->get('name') . ' — ' . $label . ($assigned ? ' (' . $assigned . ')' : ''),
            ];
        }
        return $items;
    }

    public function getUpcomingHearingItems(int $days = 7): array
    {
        $today = date('Y-m-d');
        $threshold = date('Y-m-d', strtotime("+{$days} days"));
        $items = [];

        $cases = $this->entityManager->getRDBRepository('Case')
            ->select(['id', 'name', 'cNextHearing', 'cCourt', 'assignedUserName'])
            ->where([
                'cNextHearing>=' => $today,
                'cNextHearing<=' => $threshold,
                'status!=' => self::CLOSED_STATUSES,
                'deleted' => false,
            ])
            ->order('cNextHearing', 'ASC')
            ->find();

        foreach ($cases as $case) {
            $daysUntil = (new \DateTime())->diff(new \DateTime($case->get('cNextHearing')))->days;
            $court = $case->get('cCourt');
            $severity = ($daysUntil <= 1) ? 'warning' : 'info';

            $msg = $case->get('name') . ' — דיון בעוד ' . $daysUntil . ' ימים';
            if ($court) {
                $msg .= ' (' . $court . ')';
            }

            $items[] = [
                'type' => 'upcoming_hearing',
                'severity' => $severity,
                'caseId' => $case->get('id'),
                'caseName' => $case->get('name'),
                'hearingDate' => $case->get('cNextHearing'),
                'daysUntil' => $daysUntil,
                'message' => $msg,
            ];
        }
        return $items;
    }

    public function getUpcomingHearings(int $days = 7): array
    {
        $today = date('Y-m-d');
        $threshold = date('Y-m-d', strtotime("+{$days} days"));

        $result = [];
        $cases = $this->entityManager->getRDBRepository('Case')
            ->select(['id', 'name', 'cNextHearing', 'cCourt', 'cJudge', 'assignedUserName', 'status'])
            ->where(['cNextHearing>=' => $today, 'cNextHearing<=' => $threshold, 'status!=' => self::CLOSED_STATUSES, 'deleted' => false])
            ->order('cNextHearing', 'ASC')->find();

        foreach ($cases as $case) {
            $result[] = [
                'caseId' => $case->get('id'), 'caseName' => $case->get('name'),
                'hearingDate' => $case->get('cNextHearing'), 'court' => $case->get('cCourt'),
                'judge' => $case->get('cJudge'), 'assignedUser' => $case->get('assignedUserName'),
            ];
        }
        return $result;
    }
}
