<?php

namespace MintyPHP\Tests\Module\Security\Service;

use MintyPHP\Module\Security\Service\SecurityCheckProcess;
use MintyPHP\Module\Security\Service\SecurityReportPdfService;
use MintyPHP\Module\Security\Service\SecurityReportSettingsGateway;
use MintyPHP\Module\Security\Service\SecurityReportTemplateService;
use MintyPHP\Service\Branding\BrandingLogoService;
use PHPUnit\Framework\TestCase;

class SecurityReportPdfServiceTest extends TestCase
{
    private function makeService(): SecurityReportPdfService
    {
        $branding = $this->createMock(BrandingLogoService::class);
        $branding->method('hasLogo')->willReturn(false);

        // Null tenant-logo service: render falls back to the static brand asset.
        return new SecurityReportPdfService(new SecurityCheckProcess(), $branding, null);
    }

    /**
     * @return array<string, mixed>
     */
    private function enrichedCheck(): array
    {
        $process = new SecurityCheckProcess();
        $processState = [];
        foreach ($process->manualStepKeys() as $key) {
            $processState[$key] = ['done' => true, 'at' => '2026-06-18 10:00:00'];
        }
        $processState[SecurityCheckProcess::STEP_REPORT]['fields'] = [
            SecurityCheckProcess::FIELD_CUSTOMER_REPORT => 'No critical findings.',
        ];
        $snapshot = ['version' => 1, 'items' => [
            ['type' => 'section', 'label' => 'Transport'],
            ['type' => 'check', 'key' => 'tls', 'label' => 'TLS enforced'],
            ['type' => 'check', 'key' => 'hsts', 'label' => 'HSTS header'],
            ['type' => 'section', 'label' => 'Application'],
            ['type' => 'check', 'key' => 'csrf', 'label' => 'CSRF protection'],
        ]];
        $techState = [
            'tls' => ['done' => true, 'note' => 'TLS 1.3'],
            'hsts' => ['done' => true, 'note' => ''],
            'csrf' => ['done' => false, 'note' => 'pending review'],
        ];

        return [
            'debitor_name' => 'Acme GmbH',
            'debitor_no' => 'D-100',
            'domain_url' => 'acme.de',
            'domain_no' => 'DNS-1',
            'product_name' => 'Intranet',
            'product_code' => 'intranet',
            'owner_name' => 'Jane Doe',
            'status' => SecurityCheckProcess::STATUS_IN_PROGRESS,
            'process_state' => $processState,
            'tech_schema_snapshot' => $snapshot,
            'tech_state' => $techState,
            'progress' => $process->computeProgress($processState, $snapshot, $techState),
        ];
    }

    public function testBuildReportContextMapsCheckDataIntoRenderShape(): void
    {
        $context = $this->makeService()->buildReportContext($this->enrichedCheck());

        $this->assertSame('Acme GmbH', $context['customer_name']);
        $this->assertSame('D-100', $context['customer_no']);
        $this->assertSame('acme.de', $context['domain']);
        $this->assertSame('Intranet', $context['product']);
        $this->assertSame('Jane Doe', $context['owner']);
        $this->assertSame('No critical findings.', $context['customer_report']);
        $this->assertNotSame('', $context['title']);

        // Summary mirrors the progress math (3 tech items, 2 done).
        $this->assertSame(3, $context['summary']['tech_total']);
        $this->assertSame(2, $context['summary']['tech_done']);

        // Five manual milestones, numbered with the technical step skipped.
        $this->assertCount(5, $context['steps']);
        $this->assertSame(1, $context['steps'][0]['number']);
        $this->assertTrue($context['steps'][0]['done']);
        $this->assertSame('2026-06-18 10:00:00', $context['steps'][0]['completed_at']);
        // 'report' is step 6 (the tech checklist step 5 is skipped from the milestone list).
        $this->assertSame(6, $context['steps'][4]['number']);

        // Tech items grouped under their sections, carrying state + notes.
        $this->assertCount(2, $context['tech_sections']);
        $this->assertSame('Transport', $context['tech_sections'][0]['label']);
        $this->assertCount(2, $context['tech_sections'][0]['items']);
        $this->assertSame('TLS enforced', $context['tech_sections'][0]['items'][0]['label']);
        $this->assertTrue($context['tech_sections'][0]['items'][0]['done']);
        $this->assertSame('TLS 1.3', $context['tech_sections'][0]['items'][0]['note']);
        $this->assertSame('Application', $context['tech_sections'][1]['label']);
        $this->assertFalse($context['tech_sections'][1]['items'][0]['done']);
    }

    public function testBuildReportContextHandlesEmptyCheckSafely(): void
    {
        $context = $this->makeService()->buildReportContext([]);

        $this->assertSame('', $context['customer_name']);
        $this->assertSame('', $context['domain']);
        $this->assertSame('', $context['customer_report']);
        $this->assertSame([], $context['tech_sections']);
        $this->assertSame(0, $context['summary']['total']);
        $this->assertSame(0, $context['summary']['percent']);
        // The fixed process always yields its five manual milestones, all open.
        $this->assertCount(5, $context['steps']);
        $this->assertFalse($context['steps'][0]['done']);
    }

    public function testBuildReportFilenameSlugifiesCustomerAndDomain(): void
    {
        $name = $this->makeService()->buildReportFilename($this->enrichedCheck());

        $this->assertSame('security-check-report-acme-gmbh-acme-de.pdf', $name);
    }

    public function testBuildReportFilenameFallsBackWhenNoIdentifiers(): void
    {
        $name = $this->makeService()->buildReportFilename([]);

        $this->assertSame('security-check-report.pdf', $name);
    }

    public function testRenderCustomerReportPdfProducesPdfBytes(): void
    {
        $pdf = $this->makeService()->renderCustomerReportPdf($this->enrichedCheck(), [
            'app_name' => 'CoreCore',
        ]);

        $this->assertNotSame('', $pdf);
        $this->assertStringStartsWith('%PDF-', $pdf);
    }

    public function testRenderCustomerReportPdfUsesConfiguredCustomTemplate(): void
    {
        $branding = $this->createMock(BrandingLogoService::class);
        $branding->method('hasLogo')->willReturn(false);

        $settings = $this->createMock(SecurityReportSettingsGateway::class);
        $settings->method('getTemplateHtml')->willReturn(
            '<!doctype html><html><body><h1>Custom {{customer_name}}</h1>{{checklist}}</body></html>'
        );

        $service = new SecurityReportPdfService(
            new SecurityCheckProcess(),
            $branding,
            null,
            $settings,
            new SecurityReportTemplateService(),
            null
        );

        $pdf = $service->renderCustomerReportPdf($this->enrichedCheck(), ['app_name' => 'CoreCore']);

        $this->assertStringStartsWith('%PDF-', $pdf);
    }
}
