<?php

namespace Tests\Feature\Api\Administrator;

use App\Models\User;
use App\Services\Administrator\AdminNotificationSubjectService;
use App\Services\Administrator\AdminPrintRecipientService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Laravel\Sanctum\Sanctum;
use Mockery;
use Tests\TestCase;

class AdministratorNotificationControllerTest extends TestCase
{
    use RefreshDatabase;

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

    public function test_can_get_alerts_data(): void
    {
        $user = User::factory()->create();
        Sanctum::actingAs($user);

        $mock = Mockery::mock(AdminNotificationSubjectService::class);
        $mock->shouldReceive('alertsData')
            ->once()
            ->andReturn([
                'admins' => [],
                'subjects' => [
                    'academics' => 'Academics',
                ],
                'assignedSubjects' => [],
                'tableReady' => true,
            ]);

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

        $response = $this->getJson('/api/v1/administrator/notifications/alerts');

        $response->assertOk()
            ->assertJson([
                'admins' => [],
                'assignedSubjects' => [],
                'tableReady' => true,
            ]);
    }

    public function test_save_alerts_requires_subjects_payload(): void
    {
        $user = User::factory()->create();
        Sanctum::actingAs($user);

        $response = $this->postJson('/api/v1/administrator/notifications/alerts', []);

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

    public function test_save_alerts_calls_subject_service(): void
    {
        $user = User::factory()->create();
        Sanctum::actingAs($user);

        $payload = [
            'subjects' => [
                1 => ['academics', 'finance'],
            ],
        ];

        $mock = Mockery::mock(AdminNotificationSubjectService::class);
        $mock->shouldReceive('save')
            ->once()
            ->with($payload['subjects'])
            ->andReturn([
                'message' => 'Notification subjects updated.',
                'status' => 200,
            ]);

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

        $response = $this->postJson('/api/v1/administrator/notifications/alerts', $payload);

        $response->assertOk()
            ->assertJson([
                'message' => 'Notification subjects updated.',
            ]);
    }

    public function test_can_get_print_recipients_data(): void
    {
        $user = User::factory()->create();
        Sanctum::actingAs($user);

        $mock = Mockery::mock(AdminPrintRecipientService::class);
        $mock->shouldReceive('data')
            ->once()
            ->andReturn([
                'admins' => [],
                'assigned' => [],
                'tableReady' => true,
            ]);

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

        $response = $this->getJson('/api/v1/administrator/notifications/print-recipients');

        $response->assertOk()
            ->assertJson([
                'admins' => [],
                'assigned' => [],
                'tableReady' => true,
            ]);
    }

    public function test_save_print_recipients_requires_notify_payload(): void
    {
        $user = User::factory()->create();
        Sanctum::actingAs($user);

        $response = $this->postJson('/api/v1/administrator/notifications/print-recipients', []);

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

    public function test_save_print_recipients_calls_service(): void
    {
        $user = User::factory()->create();
        Sanctum::actingAs($user);

        $payload = [
            'notify' => [
                1 => 1,
                2 => 1,
            ],
        ];

        $mock = Mockery::mock(AdminPrintRecipientService::class);
        $mock->shouldReceive('save')
            ->once()
            ->with($payload['notify'])
            ->andReturn([
                'message' => 'Print notification recipients updated.',
                'status' => 200,
            ]);

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

        $response = $this->postJson('/api/v1/administrator/notifications/print-recipients', $payload);

        $response->assertOk()
            ->assertJson([
                'message' => 'Print notification recipients updated.',
            ]);
    }
}