<?php

namespace Tests\Feature\Api\V1\AttendanceTracking;

use App\Services\AttendanceTracking\AttendanceTrackingService;
use Mockery;
use Tests\TestCase;

class AttendanceTrackingControllerTest extends TestCase
{
    protected function tearDown(): void
    {
        Mockery::close();
        parent::tearDown();
    }

    protected function mockService(): \Mockery\MockInterface
    {
        $service = Mockery::mock(AttendanceTrackingService::class);
        $this->app->instance(AttendanceTrackingService::class, $service);

        return $service;
    }

    public function test_pending_violations_returns_json_response(): void
    {
        $service = $this->mockService();

        $service->shouldReceive('getPendingViolations')
            ->once()
            ->with('2025-2026', 'Fall')
            ->andReturn([
                'students' => [
                    ['id' => 1, 'name' => 'John Doe'],
                ],
                'school_year' => '2025-2026',
                'semester' => 'Fall',
            ]);

        $response = $this->getJson('/api/attendance-tracking/pending-violations?school_year=2025-2026&semester=Fall');

        $response->assertOk()
            ->assertJson([
                'success' => true,
                'data' => [
                    'school_year' => '2025-2026',
                    'semester' => 'Fall',
                ],
            ]);
    }

    public function test_notified_violations_returns_json_response(): void
    {
        $service = $this->mockService();

        $service->shouldReceive('getNotifiedViolations')
            ->once()
            ->with('2025-2026', 'Fall')
            ->andReturn([
                'students' => [],
                'school_year' => '2025-2026',
                'semester' => 'Fall',
            ]);

        $response = $this->getJson('/api/attendance-tracking/notified-violations?school_year=2025-2026&semester=Fall');

        $response->assertOk()
            ->assertJson([
                'success' => true,
                'data' => [
                    'school_year' => '2025-2026',
                    'semester' => 'Fall',
                ],
            ]);
    }

    public function test_student_case_returns_service_payload(): void
    {
        $service = $this->mockService();

        $service->shouldReceive('getStudentCase')
            ->once()
            ->andReturn([
                'success' => true,
                'data' => [
                    'student' => ['id' => 10, 'name' => 'John Doe'],
                    'attendance' => [],
                ],
            ]);

        $response = $this->getJson('/api/attendance-tracking/student-case/10');

        $response->assertOk()
            ->assertJson([
                'success' => true,
                'data' => [
                    'student' => ['id' => 10, 'name' => 'John Doe'],
                ],
            ]);
    }

    public function test_student_case_returns_service_status_code_when_not_found(): void
    {
        $service = $this->mockService();

        $service->shouldReceive('getStudentCase')
            ->once()
            ->andReturn([
                'success' => false,
                'message' => 'Student not found',
                'status' => 404,
            ]);

        $response = $this->getJson('/api/attendance-tracking/student-case/999');

        $response->assertStatus(404)
            ->assertJson([
                'success' => false,
                'message' => 'Student not found',
            ]);
    }

    public function test_record_validates_and_returns_service_response(): void
    {
        $service = $this->mockService();

        $payload = [
            'student_id' => 10,
            'date' => '2026-03-01',
            'parent_email' => 'parent@example.com',
            'parent_name' => 'Jane Doe',
            'subject_type' => 'Absent',
        ];

        $service->shouldReceive('record')
            ->once()
            ->with($payload)
            ->andReturn([
                'success' => true,
                'message' => 'Notification queued.',
            ]);

        $response = $this->postJson('/api/attendance-tracking/record', $payload);

        $response->assertOk()
            ->assertJson([
                'success' => true,
                'message' => 'Notification queued.',
            ]);
    }

    public function test_record_returns_validation_errors_for_bad_payload(): void
    {
        $response = $this->postJson('/api/attendance-tracking/record', [
            'student_id' => 0,
            'date' => 'bad-date',
        ]);

        $response->assertStatus(422)
            ->assertJsonValidationErrors(['student_id', 'date']);
    }

    public function test_send_auto_emails_returns_service_response(): void
    {
        $service = $this->mockService();

        $service->shouldReceive('sendAutoEmails')
            ->once()
            ->with('default')
            ->andReturn([
                'success' => true,
                'sent' => 2,
                'skipped' => 1,
                'errors' => 0,
                'details' => [],
            ]);

        $response = $this->postJson('/api/attendance-tracking/send-auto-emails', [
            'variant' => 'default',
        ]);

        $response->assertOk()
            ->assertJson([
                'success' => true,
                'sent' => 2,
                'skipped' => 1,
                'errors' => 0,
            ]);
    }

    public function test_compose_returns_service_response(): void
    {
        $service = $this->mockService();

        $service->shouldReceive('compose')
            ->once()
            ->with(10, 'ABS_1', 'default', '2026-03-01')
            ->andReturn([
                'success' => true,
                'data' => [
                    'student_id' => 10,
                    'subject' => 'Test Subject',
                ],
            ]);

        $response = $this->getJson('/api/attendance-tracking/compose?student_id=10&code=ABS_1&variant=default&incident_date=2026-03-01');

        $response->assertOk()
            ->assertJson([
                'success' => true,
                'data' => [
                    'student_id' => 10,
                    'subject' => 'Test Subject',
                ],
            ]);
    }

    public function test_send_manual_email_returns_service_response(): void
    {
        $service = $this->mockService();

        $payload = [
            'student_id' => 10,
            'to' => 'parent@example.com',
            'subject' => 'Hello',
            'body_html' => 'Body',
            'code' => 'ABS_1',
            'variant' => 'default',
            'incident_date' => '2026-03-01',
        ];

        $service->shouldReceive('sendEmailManual')
            ->once()
            ->with($payload)
            ->andReturn([
                'success' => true,
                'message' => 'Email sent successfully.',
            ]);

        $response = $this->postJson('/api/attendance-tracking/send-manual-email', $payload);

        $response->assertOk()
            ->assertJson([
                'success' => true,
                'message' => 'Email sent successfully.',
            ]);
    }

    public function test_send_manual_email_validates_payload(): void
    {
        $response = $this->postJson('/api/attendance-tracking/send-manual-email', [
            'student_id' => 0,
            'to' => 'not-an-email',
        ]);

        $response->assertStatus(422)
            ->assertJsonValidationErrors(['student_id', 'to', 'subject', 'body_html', 'code']);
    }

    public function test_parents_info_returns_service_response(): void
    {
        $service = $this->mockService();

        $service->shouldReceive('parentsInfo')
            ->once()
            ->with(10)
            ->andReturn([
                'success' => true,
                'data' => [
                    'primary' => ['email' => 'parent@example.com'],
                    'secondary' => ['email' => 'second@example.com'],
                ],
            ]);

        $response = $this->getJson('/api/attendance-tracking/parents-info?student_id=10');

        $response->assertOk()
            ->assertJson([
                'success' => true,
                'data' => [
                    'primary' => ['email' => 'parent@example.com'],
                    'secondary' => ['email' => 'second@example.com'],
                ],
            ]);
    }

    public function test_save_notification_note_returns_service_response(): void
    {
        $service = $this->mockService();

        $payload = [
            'student_id' => 10,
            'code' => 'ABS_1',
            'note' => 'Called parent',
            'incident_date' => '2026-03-01',
        ];

        $service->shouldReceive('saveNotificationNote')
            ->once()
            ->with($payload)
            ->andReturn([
                'success' => true,
                'message' => 'Note saved.',
            ]);

        $response = $this->postJson('/api/attendance-tracking/save-notification-note', $payload);

        $response->assertOk()
            ->assertJson([
                'success' => true,
                'message' => 'Note saved.',
            ]);
    }

    public function test_save_notification_note_validates_payload(): void
    {
        $response = $this->postJson('/api/attendance-tracking/save-notification-note', [
            'student_id' => 0,
            'code' => '',
            'note' => '',
        ]);

        $response->assertStatus(422)
            ->assertJsonValidationErrors(['student_id', 'code', 'note']);
    }
}
