<?php

namespace Tests\Feature\Api;

use App\Models\User;
use App\Services\Badges\BadgeFormDataService;
use App\Services\Badges\BadgePdfService;
use App\Services\Badges\BadgePrintLogService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Laravel\Sanctum\Sanctum;
use Mockery;
use Tests\TestCase;

class BadgeControllerTest extends TestCase
{
    use RefreshDatabase;

    protected function authenticate(): User
    {
        $user = User::factory()->create();
        Sanctum::actingAs($user);

        return $user;
    }

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

    public function test_form_data_returns_success_response(): void
    {
        $this->authenticate();

        $mock = Mockery::mock(BadgeFormDataService::class);
        $mock->shouldReceive('build')
            ->once()
            ->with('2025-2026', [10, 20], 'teacher')
            ->andReturn([
                'users' => [],
                'schoolYears' => ['2025-2026'],
                'selectedYear' => '2025-2026',
                'selectedUserIds' => [10, 20],
                'rolesTabs' => ['teacher' => 'Teachers'],
                'active_role' => 'teacher',
            ]);

        $this->app->instance(BadgeFormDataService::class, $mock);

        $response = $this->getJson('/api/badges/form-data?school_year=2025-2026&user_ids=10,20&active_role=teacher');

        $response->assertOk()
            ->assertJson([
                'ok' => true,
                'data' => [
                    'selectedYear' => '2025-2026',
                    'selectedUserIds' => [10, 20],
                    'active_role' => 'teacher',
                ],
            ]);
    }

    public function test_print_status_returns_success_response(): void
    {
        $this->authenticate();

        $mock = Mockery::mock(BadgePrintLogService::class);
        $mock->shouldReceive('getStatus')
            ->once()
            ->with([5, 7], '2025-2026')
            ->andReturn([
                5 => [
                    'count' => 2,
                    'last_printed_at' => '2026-03-06 12:00:00',
                    'last_printed_by' => 1,
                ],
            ]);

        $this->app->instance(BadgePrintLogService::class, $mock);

        $response = $this->getJson('/api/badges/print-status?user_ids=5,7&school_year=2025-2026');

        $response->assertOk()
            ->assertJson([
                'ok' => true,
                'data' => [
                    '5' => [
                        'count' => 2,
                        'last_printed_at' => '2026-03-06 12:00:00',
                        'last_printed_by' => 1,
                    ],
                ],
            ]);
    }

    public function test_print_status_returns_500_when_service_throws(): void
    {
        $this->authenticate();

        $mock = Mockery::mock(BadgePrintLogService::class);
        $mock->shouldReceive('getStatus')
            ->once()
            ->andThrow(new \RuntimeException('db failed'));

        $this->app->instance(BadgePrintLogService::class, $mock);

        $response = $this->getJson('/api/badges/print-status?user_ids=5,7');

        $response->assertStatus(500)
            ->assertJson([
                'ok' => false,
                'error' => 'Failed to query status',
            ]);
    }

    public function test_log_print_returns_success_response(): void
    {
        $authUser = $this->authenticate();

        $mock = Mockery::mock(BadgePrintLogService::class);
        $mock->shouldReceive('log')
            ->once()
            ->with(
                [10, 20],
                $authUser->id,
                '2025-2026',
                ['10' => 'Teacher'],
                ['10' => '3-A']
            )
            ->andReturn(2);

        $this->app->instance(BadgePrintLogService::class, $mock);

        $response = $this->postJson('/api/badges/log-print', [
            'user_ids' => [10, 20],
            'school_year' => '2025-2026',
            'roles' => ['10' => 'Teacher'],
            'classes' => ['10' => '3-A'],
        ]);

        $response->assertOk()
            ->assertJson([
                'ok' => true,
                'inserted' => 2,
            ]);
    }

    public function test_log_print_returns_500_when_service_throws(): void
    {
        $this->authenticate();

        $mock = Mockery::mock(BadgePrintLogService::class);
        $mock->shouldReceive('log')
            ->once()
            ->andThrow(new \RuntimeException('insert failed'));

        $this->app->instance(BadgePrintLogService::class, $mock);

        $response = $this->postJson('/api/badges/log-print', [
            'user_ids' => [10],
        ]);

        $response->assertStatus(500)
            ->assertJson([
                'ok' => false,
                'error' => 'insert failed',
            ]);
    }

    public function test_generate_pdf_returns_pdf_response(): void
    {
        $authUser = $this->authenticate();

        $mock = Mockery::mock(BadgePdfService::class);
        $mock->shouldReceive('generate')
            ->once()
            ->with(
                [10, 20],
                '2025-2026',
                ['10' => 'Teacher'],
                ['10' => '3-A'],
                $authUser->id
            )
            ->andReturn(response('fake-pdf-content', 200, [
                'Content-Type' => 'application/pdf',
                'Content-Disposition' => 'inline; filename="Staff_Badges.pdf"',
            ]));

        $this->app->instance(BadgePdfService::class, $mock);

        $response = $this->post('/api/badges/pdf', [
            'user_ids' => [10, 20],
            'school_year' => '2025-2026',
            'roles' => ['10' => 'Teacher'],
            'classes' => ['10' => '3-A'],
        ]);

        $response->assertOk();
        $response->assertHeader('Content-Type', 'application/pdf');
        $this->assertStringContainsString(
            'inline; filename="Staff_Badges.pdf"',
            $response->headers->get('Content-Disposition')
        );
        $this->assertSame('fake-pdf-content', $response->getContent());
    }

    public function test_generate_pdf_validates_required_user_ids(): void
    {
        $this->authenticate();

        $response = $this->postJson('/api/badges/pdf', [
            'school_year' => '2025-2026',
        ]);

        $response->assertStatus(422)
            ->assertJsonValidationErrors(['user_ids']);
    }

    public function test_log_print_validates_required_user_ids(): void
    {
        $this->authenticate();

        $response = $this->postJson('/api/badges/log-print', []);

        $response->assertStatus(422)
            ->assertJsonValidationErrors(['user_ids']);
    }

    public function test_endpoints_require_authentication(): void
    {
        $this->getJson('/api/badges/form-data')->assertStatus(401);
        $this->getJson('/api/badges/print-status')->assertStatus(401);
        $this->postJson('/api/badges/log-print', ['user_ids' => [1]])->assertStatus(401);
        $this->postJson('/api/badges/pdf', ['user_ids' => [1]])->assertStatus(401);
    }
}