<?php

namespace App\Tests\Entity;

use App\Entity\Advert;
use App\Entity\OrderNumber;
use App\Entity\PaymentReminder;
use PHPUnit\Framework\TestCase;

class PaymentReminderTest extends TestCase
{
    private function createAdvert(): Advert
    {
        $order = new OrderNumber('04/2026-99003');

        return new Advert($order, 'test-secret');
    }

    public function testConstructorMinimalArgs(): void
    {
        $advert = $this->createAdvert();
        $reminder = new PaymentReminder($advert, PaymentReminder::STEP_REMINDER_15);

        $this->assertNull($reminder->getId());
        $this->assertSame($advert, $reminder->getAdvert());
        $this->assertSame(PaymentReminder::STEP_REMINDER_15, $reminder->getStep());
        $this->assertNull($reminder->getDetails());
        $this->assertInstanceOf(\DateTimeImmutable::class, $reminder->getSentAt());
    }

    public function testConstructorWithDetails(): void
    {
        $advert = $this->createAdvert();
        $reminder = new PaymentReminder($advert, PaymentReminder::STEP_FORMAL_NOTICE, 'Email envoyé à client@test.fr');

        $this->assertSame('Email envoyé à client@test.fr', $reminder->getDetails());
    }

    public function testStepConstants(): void
    {
        $this->assertSame('reminder_15', PaymentReminder::STEP_REMINDER_15);
        $this->assertSame('warning_10', PaymentReminder::STEP_WARNING_10);
        $this->assertSame('suspension_5', PaymentReminder::STEP_SUSPENSION_WARNING_5);
        $this->assertSame('final_reminder_3', PaymentReminder::STEP_FINAL_REMINDER_3);
        $this->assertSame('suspension_1', PaymentReminder::STEP_SUSPENSION_1);
        $this->assertSame('formal_notice', PaymentReminder::STEP_FORMAL_NOTICE);
        $this->assertSame('termination_15', PaymentReminder::STEP_TERMINATION_WARNING);
        $this->assertSame('termination_30', PaymentReminder::STEP_TERMINATION);
    }

    public function testGetStepLabelKnownSteps(): void
    {
        $advert = $this->createAdvert();

        $cases = [
            PaymentReminder::STEP_REMINDER_15 => 'Rappel de paiement',
            PaymentReminder::STEP_WARNING_10 => 'Rappel + avertissement',
            PaymentReminder::STEP_SUSPENSION_WARNING_5 => 'Avertissement suspension services',
            PaymentReminder::STEP_FINAL_REMINDER_3 => 'Ultime rappel',
            PaymentReminder::STEP_SUSPENSION_1 => 'Suspension des services',
            PaymentReminder::STEP_FORMAL_NOTICE => 'Mise en demeure',
            PaymentReminder::STEP_TERMINATION_WARNING => 'Avertissement resiliation + suppression donnees',
            PaymentReminder::STEP_TERMINATION => 'Resiliation contrat + recouvrement legal',
        ];

        foreach ($cases as $step => $expectedLabel) {
            $reminder = new PaymentReminder($advert, $step);
            $this->assertSame($expectedLabel, $reminder->getStepLabel(), "Label mismatch for step: $step");
        }
    }

    public function testGetStepLabelUnknownStep(): void
    {
        $advert = $this->createAdvert();
        $reminder = new PaymentReminder($advert, 'unknown_step');
        $this->assertSame('unknown_step', $reminder->getStepLabel());
    }

    public function testGetSeverityKnownSteps(): void
    {
        $advert = $this->createAdvert();

        $cases = [
            PaymentReminder::STEP_REMINDER_15 => 'info',
            PaymentReminder::STEP_WARNING_10 => 'warning',
            PaymentReminder::STEP_SUSPENSION_WARNING_5 => 'danger',
            PaymentReminder::STEP_FINAL_REMINDER_3 => 'danger',
            PaymentReminder::STEP_SUSPENSION_1 => 'critical',
            PaymentReminder::STEP_FORMAL_NOTICE => 'critical',
            PaymentReminder::STEP_TERMINATION_WARNING => 'critical',
            PaymentReminder::STEP_TERMINATION => 'critical',
        ];

        foreach ($cases as $step => $expectedSeverity) {
            $reminder = new PaymentReminder($advert, $step);
            $this->assertSame($expectedSeverity, $reminder->getSeverity(), "Severity mismatch for step: $step");
        }
    }

    public function testGetSeverityUnknownStep(): void
    {
        $advert = $this->createAdvert();
        $reminder = new PaymentReminder($advert, 'unknown_step');
        $this->assertSame('info', $reminder->getSeverity());
    }

    public function testStepsConfigCoversAllStepConstants(): void
    {
        $stepConstants = [
            PaymentReminder::STEP_REMINDER_15,
            PaymentReminder::STEP_WARNING_10,
            PaymentReminder::STEP_SUSPENSION_WARNING_5,
            PaymentReminder::STEP_FINAL_REMINDER_3,
            PaymentReminder::STEP_SUSPENSION_1,
            PaymentReminder::STEP_FORMAL_NOTICE,
            PaymentReminder::STEP_TERMINATION_WARNING,
            PaymentReminder::STEP_TERMINATION,
        ];

        foreach ($stepConstants as $step) {
            $this->assertArrayHasKey($step, PaymentReminder::STEPS_CONFIG, "STEPS_CONFIG is missing step: $step");
            $this->assertArrayHasKey('days', PaymentReminder::STEPS_CONFIG[$step]);
            $this->assertArrayHasKey('label', PaymentReminder::STEPS_CONFIG[$step]);
            $this->assertArrayHasKey('severity', PaymentReminder::STEPS_CONFIG[$step]);
        }
    }

    public function testSentAtTimestamp(): void
    {
        $advert = $this->createAdvert();
        $before = new \DateTimeImmutable();
        $reminder = new PaymentReminder($advert, PaymentReminder::STEP_REMINDER_15);
        $after = new \DateTimeImmutable();

        $this->assertGreaterThanOrEqual($before, $reminder->getSentAt());
        $this->assertLessThanOrEqual($after, $reminder->getSentAt());
    }
}
