<?php

namespace Tests\Feature;

use App\Models\AttendanceRecord;
use App\Models\AttendanceSetting;
use App\Models\Branch;
use App\Models\Employee;
use App\Models\User;
use App\Services\ErpNotificationService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\UploadedFile;
use Tests\TestCase;

class CrossCuttingErpExperienceTest extends TestCase
{
    use RefreshDatabase;

    protected function setUp(): void
    {
        parent::setUp();
        $this->seed();
    }

    public function test_role_aware_dashboard_reports_search_and_notifications_are_connected(): void
    {
        $owner = User::where('email', 'owner@almadina.ae')->firstOrFail();
        $receptionist = User::where('email', 'reception@almadina.ae')->firstOrFail();
        $accountant = User::where('email', 'accountant@almadina.ae')->firstOrFail();

        $this->actingAs($owner)->get(route('app.dashboard'))
            ->assertOk()
            ->assertSee('Employees Present')
            ->assertSee('Government Fees')
            ->assertSee('Employee Document Expiry')
            ->assertSee('Pending Approvals');

        $ownerSearch = $this->actingAs($owner)->getJson(route('app.global_search', ['q' => 'EMP-009']))
            ->assertOk()->json('results');
        $this->assertContains('Employee', collect($ownerSearch)->pluck('type')->all());

        $receptionSearch = $this->actingAs($receptionist)->getJson(route('app.global_search', ['q' => 'EMP-009']))
            ->assertOk()->json('results');
        $this->assertNotContains('Employee', collect($receptionSearch)->pluck('type')->all());

        $this->actingAs($accountant)->get(route('app.reports.index'))
            ->assertOk()->assertSee('HR & Payroll Summary', false)->assertSee('Payroll net');
        $this->actingAs($accountant)->get(route('app.reports.index', ['export' => 'csv']))
            ->assertOk()
            ->assertHeader('content-type', 'text/csv; charset=UTF-8')
            ->assertDownload();

        app(ErpNotificationService::class)->notifyUser(
            $owner,
            'system',
            'Acceptance alert',
            'Cross-cutting notification workflow is connected.',
            route('app.dashboard'),
        );
        $notification = $owner->fresh()->unreadNotifications()->firstOrFail();
        $this->actingAs($owner)->get(route('app.notifications.index'))
            ->assertOk()->assertSee('Acceptance alert')->assertSee('Cross-cutting notification workflow is connected.');
        $this->actingAs($owner)->post(route('app.notifications.read', $notification->id))
            ->assertRedirect(route('app.dashboard'));
        $this->assertNotNull($notification->fresh()->read_at);
    }

    public function test_own_branch_user_cannot_expand_scope_with_the_branch_switcher(): void
    {
        $receptionist = User::where('email', 'reception@almadina.ae')->firstOrFail();
        $foreignAllowedBranch = Branch::where('tenant_id', $receptionist->tenant_id)
            ->whereKeyNot($receptionist->default_branch_id)->firstOrFail();

        $this->actingAs($receptionist)->post(route('app.switch_branch'), ['branch_id' => 'all'])->assertForbidden();
        $this->actingAs($receptionist)->post(route('app.switch_branch'), ['branch_id' => $foreignAllowedBranch->id])->assertRedirect();
        $this->assertNotSame($foreignAllowedBranch->id, session('active_branch_id'));
    }

    public function test_attendance_self_service_import_calendar_and_grouped_settings_are_connected(): void
    {
        $owner = User::where('email', 'owner@almadina.ae')->firstOrFail();
        $employee = Employee::where('employee_code', 'EMP-009')->firstOrFail();
        $owner->update(['employee_id' => $employee->id]);

        $this->actingAs($owner)->get(route('app.settings.index'))
            ->assertOk()->assertSee('HR, attendance & payroll')->assertSee('Billing & VAT');
        $this->actingAs($owner)->post(route('app.settings.hr.update'), [
            'probation_days' => 180,
            'document_alert_days' => 90,
            'week_starts_on' => 'monday',
            'allow_web_punch' => 1,
            'correction_requires_approval' => 1,
            'minimum_overtime_minutes' => 30,
            'currency' => 'AED',
            'salary_payment_day' => 28,
            'payroll_day_basis' => 'calendar_days',
        ])->assertRedirect();
        $this->assertTrue((bool) AttendanceSetting::firstOrFail()->settings['allow_web_punch']);

        $this->actingAs($owner)->post(route('app.attendance.punch'), ['action' => 'check_in'])->assertRedirect();
        $this->assertNotNull(AttendanceRecord::where('employee_id', $employee->id)->whereDate('attendance_date', today())->firstOrFail()->actual_check_in);
        $this->actingAs($owner)->post(route('app.attendance.punch'), ['action' => 'check_out'])->assertRedirect();
        $this->assertNotNull(AttendanceRecord::where('employee_id', $employee->id)->whereDate('attendance_date', today())->firstOrFail()->actual_check_out);

        $csv = "employee_code,attendance_date,check_in,check_out,status,notes\nEMP-009,2026-08-01,09:10,18:05,late,Validated import\n";
        $this->actingAs($owner)->post(route('app.attendance.import'), [
            'attendance_file' => UploadedFile::fake()->createWithContent('attendance.csv', $csv),
        ])->assertRedirect()->assertSessionHas('status', '1 attendance row(s) imported.');
        $this->assertDatabaseHas('attendance_records', [
            'employee_id' => $employee->id,
            'attendance_date' => '2026-08-01 00:00:00',
            'source' => 'import',
            'status' => 'late',
        ]);

        $this->actingAs($owner)->get(route('app.attendance.index', ['view' => 'calendar', 'date' => '2026-08-01']))
            ->assertOk()->assertSee('1 present')->assertSee('Calendar');
    }
}
