<?php

namespace MintyPHP\Tests\Module\Helpdesk\Service;

use MintyPHP\Module\Helpdesk\Service\SystemRecommendationEngine;
use PHPUnit\Framework\TestCase;

class SystemRecommendationEngineTest extends TestCase
{
    public function testBuildRecommendationsAppliesRulesSortsAndLimits(): void
    {
        $engine = new SystemRecommendationEngine();
        $config = [
            'max_items' => 5,
            'rules' => [
                'escalation_overdue' => ['enabled' => true, 'priority' => 100, 'min_overdue_minutes' => 0],
                'high_risk_aging' => ['enabled' => true, 'priority' => 90, 'codes' => ['MAX', 'HOCH'], 'min_age_hours' => 8],
                'unassigned_open' => ['enabled' => true, 'priority' => 80, 'min_age_hours' => 2],
                'stale_open' => ['enabled' => true, 'priority' => 70, 'min_age_hours' => 48],
                'customer_backlog' => ['enabled' => true, 'priority' => 60, 'min_open_tickets' => 3],
            ],
        ];

        $tickets = [
            $this->openTicket('T001', 80, 'USR1'),
            $this->openTicket('T002', 10, 'USR2'),
            $this->openTicket('T003', 6, ''),
            $this->openTicket('T004', 60, 'USR3'),
            $this->openTicket('T005', 5, 'USR4'),
            ['No' => 'T999', 'Ticket_State' => 'Closed', 'Last_Activity_Date' => $this->isoHoursAgo(120)],
        ];

        $escalationHealth = [
            'ok' => true,
            'entries' => [
                ['ticket_no' => 'T001', 'escalation_code' => 'MAX', 'overdue_seconds' => 72000],
                ['ticket_no' => 'T004', 'escalation_code' => 'NORMAL', 'overdue_seconds' => 600],
                ['ticket_no' => 'T001', 'escalation_code' => 'MAX', 'overdue_seconds' => 72000], // duplicate
            ],
            'matches' => [
                ['ticket_no' => 'T001', 'escalation_code' => 'MAX', 'age_hours' => 80, 'is_overdue' => true],
                ['ticket_no' => 'T002', 'escalation_code' => 'HOCH', 'age_hours' => 10, 'is_overdue' => false],
                ['ticket_no' => 'T004', 'escalation_code' => 'NORMAL', 'age_hours' => 60, 'is_overdue' => true],
            ],
        ];

        $result = $engine->buildRecommendations($tickets, $escalationHealth, $config);

        $this->assertCount(5, $result['recommendations']);
        $this->assertSame('escalation_overdue', $result['recommendations'][0]['rule_id']);
        $this->assertSame('T001', $result['recommendations'][0]['ticket_no']);
        $this->assertSame('escalation_overdue', $result['recommendations'][1]['rule_id']);
        $this->assertSame('high_risk_aging', $result['recommendations'][2]['rule_id']);
        $this->assertSame('helpdesk.recommendation.high_risk_aging', $result['recommendations'][2]['message_key']);
        $this->assertSame(
            ['escalation_overdue', 'high_risk_aging', 'unassigned_open', 'stale_open', 'customer_backlog'],
            $result['meta']['applied_rules']
        );
        $this->assertTrue($result['meta']['escalation_data_available']);
    }

    public function testBuildRecommendationsSkipsEscalationRulesWhenUnavailable(): void
    {
        $engine = new SystemRecommendationEngine();
        $config = [
            'max_items' => 10,
            'rules' => [
                'escalation_overdue' => ['enabled' => true, 'priority' => 100, 'min_overdue_minutes' => 0],
                'high_risk_aging' => ['enabled' => true, 'priority' => 90, 'codes' => ['MAX', 'HOCH'], 'min_age_hours' => 8],
                'unassigned_open' => ['enabled' => true, 'priority' => 80, 'min_age_hours' => 2],
                'stale_open' => ['enabled' => true, 'priority' => 70, 'min_age_hours' => 48],
                'customer_backlog' => ['enabled' => true, 'priority' => 60, 'min_open_tickets' => 1],
            ],
        ];

        $tickets = [
            $this->openTicket('T010', 72, ''),
        ];

        $result = $engine->buildRecommendations($tickets, null, $config);
        $ruleIds = array_map(static fn (array $item): string => (string) $item['rule_id'], $result['recommendations']);

        $this->assertFalse($result['meta']['escalation_data_available']);
        $this->assertNotContains('escalation_overdue', $ruleIds);
        $this->assertNotContains('high_risk_aging', $ruleIds);
        $this->assertContains('unassigned_open', $ruleIds);
        $this->assertContains('stale_open', $ruleIds);
        $this->assertContains('customer_backlog', $ruleIds);
    }

    public function testBuildRecommendationsCreatesBacklogRecommendationWithOldestTicket(): void
    {
        $engine = new SystemRecommendationEngine();
        $config = [
            'max_items' => 5,
            'rules' => [
                'escalation_overdue' => ['enabled' => false, 'priority' => 100, 'min_overdue_minutes' => 0],
                'high_risk_aging' => ['enabled' => false, 'priority' => 90, 'codes' => ['MAX', 'HOCH'], 'min_age_hours' => 8],
                'unassigned_open' => ['enabled' => false, 'priority' => 80, 'min_age_hours' => 2],
                'stale_open' => ['enabled' => false, 'priority' => 70, 'min_age_hours' => 48],
                'customer_backlog' => ['enabled' => true, 'priority' => 60, 'min_open_tickets' => 3],
            ],
        ];

        $tickets = [
            $this->openTicket('T100', 12, 'A'),
            $this->openTicket('T101', 44, 'B'),
            $this->openTicket('T102', 9, 'C'),
        ];

        $result = $engine->buildRecommendations($tickets, null, $config);

        $this->assertCount(1, $result['recommendations']);
        $this->assertSame('customer_backlog', $result['recommendations'][0]['rule_id']);
        $this->assertSame('T101', $result['recommendations'][0]['ticket_no']);
        $this->assertSame(3, $result['recommendations'][0]['message_params']['open_tickets']);
    }

    /**
     * @return array<string, mixed>
     */
    private function openTicket(string $ticketNo, int $ageHours, string $supportUserName): array
    {
        return [
            'No' => $ticketNo,
            'Ticket_State' => 'Open',
            'Support_User_Name' => $supportUserName,
            'Last_Activity_Date' => $this->isoHoursAgo($ageHours),
        ];
    }

    private function isoHoursAgo(int $hours): string
    {
        $dt = new \DateTimeImmutable('now', new \DateTimeZone('UTC'));
        $dt = $dt->modify('-' . max(0, $hours) . ' hours');

        return $dt->format('Y-m-d\\TH:i:00\\Z');
    }
}
