<?php

namespace Tests\Feature\Api\V1\FullSurface;

use App\Models\User;
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;

class ApiPermissionMatrixExhaustiveContractTest extends FullSurfaceE2EContractCase
{
    public function test_core_domain_permission_matrix_is_enforced_across_roles(): void
    {
        foreach ($this->permissionMatrix() as $label => $case) {
            /** @var User $actor */
            $actor = $case['actor'];
            $response = $this->requestAs($actor, $case['method'], $case['path'], $case['payload'] ?? []);

            $this->assertStatusIn($response, $case['allowed_statuses'], $label);
            $this->assertNoServerError($response, $label);
        }
    }

    public function test_admin_only_mutations_are_not_available_to_lower_roles(): void
    {
        foreach ($this->adminOnlyMutations() as [$method, $path, $payload]) {
            foreach ([$this->parent, $this->teacher, $this->studentUser] as $actor) {
                $response = $this->requestAs($actor, $method, $path, $payload);

                $this->assertStatusIn($response, [302, 401, 403, 404, 405, 419, 422], "$method $path denied to {$actor->id}");
                $this->assertNoServerError($response, "$method $path denied to {$actor->id}");
            }
        }
    }

    public function test_student_role_cannot_access_parent_teacher_or_admin_portals(): void
    {
        foreach ($this->studentForbiddenPaths() as $path) {
            $response = $this->requestAs($this->studentUser, 'GET', $path);

            $this->assertStatusIn($response, [302, 401, 403, 404, 405, 419, 422], "student forbidden $path");
            $this->assertNoServerError($response, "student forbidden $path");
        }
    }

    /** @return array<string,array{actor:User,method:string,path:string,payload?:array<string,mixed>,allowed_statuses:list<int>}> */
    private function permissionMatrix(): array
    {
        return [
            'admin can reach users index' => ['actor' => $this->admin, 'method' => 'GET', 'path' => 'api/v1/users', 'allowed_statuses' => [200, 204, 302, 401, 403, 404, 405, 419, 422]],
            'teacher can reach teacher classes' => ['actor' => $this->teacher, 'method' => 'GET', 'path' => 'api/v1/teacher/classes', 'allowed_statuses' => [200, 204, 302, 401, 403, 404, 405, 419, 422]],
            'parent can reach parent profile' => ['actor' => $this->parent, 'method' => 'GET', 'path' => 'api/v1/parents/profile', 'allowed_statuses' => [200, 204, 302, 401, 403, 404, 405, 419, 422]],
            'parent denied users index' => ['actor' => $this->parent, 'method' => 'GET', 'path' => 'api/v1/users', 'allowed_statuses' => [302, 401, 403, 404, 405, 419, 422]],
            'teacher denied role permissions' => ['actor' => $this->teacher, 'method' => 'GET', 'path' => 'api/v1/roles', 'allowed_statuses' => [302, 401, 403, 404, 405, 419, 422]],
            'student denied finance reports' => ['actor' => $this->studentUser, 'method' => 'GET', 'path' => 'api/v1/finance/reports', 'allowed_statuses' => [302, 401, 403, 404, 405, 419, 422]],
        ];
    }

    /** @return list<array{string,string,array<string,mixed>}> */
    private function adminOnlyMutations(): array
    {
        return [
            ['POST', 'api/v1/users', $this->validUserPayload((int) $this->ids['roleId'])],
            ['POST', 'api/v1/students', $this->payloadFor('POST', 'api/v1/students')],
            ['POST', 'api/v1/school-years', ['name' => '2099-2100', 'start_date' => '2099-09-01', 'end_date' => '2100-06-01']],
            ['POST', 'api/v1/inventory/items', $this->payloadFor('POST', 'api/v1/inventory/items')],
            ['POST', 'api/v1/finance/payments', $this->payloadFor('POST', 'api/v1/finance/payments')],
        ];
    }

    /** @return list<string> */
    private function studentForbiddenPaths(): array
    {
        return [
            'api/v1/admin/dashboard',
            'api/v1/teacher/classes',
            'api/v1/parents/profile',
            'api/v1/users',
            'api/v1/inventory/items',
            'api/v1/finance/reports',
        ];
    }
}
