<?php

namespace Tests\Unit\SiteReadiness;

use App\SiteReadiness\CheckResult;
use App\SiteReadiness\ReadinessCheck;
use App\SiteReadiness\ReadinessReport;
use App\SiteReadiness\Status;
use Tests\TestCase;

class ReadinessReportTest extends TestCase
{
    protected function tearDown(): void
    {
        parent::tearDown();
        // Reset the HooksAdapter static singleton so filters don't leak between tests.
        $ref = new \ReflectionProperty(\HooksAdapter::class, 'instance');
        $ref->setAccessible(true);
        $ref->setValue(null, null);
    }

    private function check(string $group, string $label, Status $status): ReadinessCheck
    {
        return new class($group, $label, $status) implements ReadinessCheck {
            public function __construct(private string $g, private string $l, private Status $s) {}
            public function group(): string { return $this->g; }
            public function label(): string { return $this->l; }
            public function run(): CheckResult { return new CheckResult($this->s, 'detail'); }
            public function hint(): string { return 'fix it'; }
        };
    }

    public function test_groups_results_and_counts_summary(): void
    {
        $report = (new ReadinessReport([
            $this->check('Environment', 'A', Status::OK),
            $this->check('Environment', 'B', Status::FAIL),
            $this->check('Mail', 'C', Status::WARN),
        ]))->run();

        $this->assertSame(['ok' => 1, 'warn' => 1, 'fail' => 1], $report['summary']);
        $this->assertCount(2, $report['groups']['Environment']);
        $this->assertSame('B', $report['groups']['Environment'][1]['label']);
        $this->assertSame(Status::FAIL, $report['groups']['Environment'][1]['status']);
    }

    public function test_plugins_can_add_checks_via_filter(): void
    {
        \HooksAdapter::add_filter('site_readiness_checks', function (array $checks) {
            $checks[] = $this->check('Integrations', 'Plugin check', Status::OK);
            return $checks;
        });

        $report = (new ReadinessReport([]))->run();

        $this->assertArrayHasKey('Integrations', $report['groups']);
        $this->assertSame('Plugin check', $report['groups']['Integrations'][0]['label']);
    }

    public function test_a_throwing_check_is_isolated_as_fail(): void
    {
        $throwing = new class implements ReadinessCheck {
            public function group(): string { return 'Environment'; }
            public function label(): string { return 'ThrowingCheck'; }
            public function run(): CheckResult { throw new \RuntimeException('boom'); }
            public function hint(): string { return 'hint'; }
        };

        $report = (new ReadinessReport([$throwing]))->run();

        // Must not throw — we assert a result was returned.
        $this->assertArrayHasKey('groups', $report);
        $this->assertArrayHasKey('summary', $report);

        // A FAIL entry must appear under the 'Errors' group.
        $this->assertArrayHasKey('Errors', $report['groups']);
        $errorRows = $report['groups']['Errors'];
        $this->assertNotEmpty($errorRows);

        $detail = $errorRows[0]['detail'];
        $this->assertStringContainsString('boom', $detail);
        $this->assertSame(Status::FAIL, $errorRows[0]['status']);

        // Summary must count at least one failure.
        $this->assertGreaterThanOrEqual(1, $report['summary']['fail']);
    }
}
