<?php

namespace Tests\Feature;

use App\Models\Server;
use App\Services\HardeningService;
use App\Services\PostureService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Mockery;
use Tests\TestCase;

class PostureServiceTest extends TestCase
{
    use RefreshDatabase;

    protected function tearDown(): void
    {
        Mockery::close();
        parent::tearDown();
    }

    private function server(): Server
    {
        return Server::create(['name' => 'box', 'ip' => '10.0.0.1', 'ssh_port' => 22, 'status' => 'online']);
    }

    /** @param array<int,array<string,mixed>> $state */
    private function scoreWith(array $state): array
    {
        $hardening = Mockery::mock(HardeningService::class);
        $hardening->shouldReceive('state')->andReturn($state);

        return (new PostureService($hardening))->score($this->server());
    }

    private function item(string $key, bool $secure, bool $supported = true, bool $neutral = false): array
    {
        return ['key' => $key, 'label' => $key, 'detail' => '', 'featureOn' => false, 'secure' => $secure, 'supported' => $supported, 'reason' => $supported ? null : 'x', 'neutral' => $neutral];
    }

    public function test_score_is_the_ratio_of_passing_applicable_gates(): void
    {
        $r = $this->scoreWith([
            $this->item('ssh_root', true),
            $this->item('ssh_password', true),
            $this->item('fail2ban', true),
            $this->item('firewall', false), // 3 of 4 secure
        ]);

        $this->assertSame(75, $r['score']);
        $this->assertSame(3, $r['passed']);
        $this->assertSame(4, $r['applicable']);
        $this->assertSame('fair', $r['rating']);
    }

    public function test_all_secure_is_a_strong_hundred(): void
    {
        $r = $this->scoreWith([$this->item('a', true), $this->item('b', true)]);

        $this->assertSame(100, $r['score']);
        $this->assertSame('strong', $r['rating']);
    }

    public function test_neutral_and_unsupported_items_do_not_count(): void
    {
        $r = $this->scoreWith([
            $this->item('ssh_root', true),                              // counts, secure
            $this->item('unattended', false, neutral: true),           // neutral → excluded
            $this->item('firewall', false, supported: false),          // unsupported → excluded
        ]);

        $this->assertSame(1, $r['applicable']); // only ssh_root counts
        $this->assertSame(100, $r['score']);    // 1/1 secure
    }

    public function test_all_failing_is_weak(): void
    {
        $r = $this->scoreWith([$this->item('a', false), $this->item('b', false)]);

        $this->assertSame(0, $r['score']);
        $this->assertSame('weak', $r['rating']);
    }

    public function test_no_applicable_checks_defaults_to_a_full_score(): void
    {
        $r = $this->scoreWith([$this->item('unattended', false, neutral: true)]);

        $this->assertSame(0, $r['applicable']);
        $this->assertSame(100, $r['score']); // nothing to fail → not penalised
    }
}
