<?php

namespace Tests\Feature;

use App\Enums\AppointmentStatus;
use App\Enums\UserRole;
use App\Models\Appointment;
use App\Models\Business;
use App\Models\Customer;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Str;
use Tests\TestCase;

class ReportsBackendTest extends TestCase
{
    use RefreshDatabase;

    public function test_report_pages_render_from_database_queries(): void
    {
        $this->seed();
        [$owner, $business] = $this->ownerAndBusiness();

        foreach ([
            route('admin.reports.index'),
            route('admin.reports.bookings'),
            route('admin.reports.revenue'),
            route('admin.reports.staff'),
            route('admin.reports.services'),
            route('admin.reports.customers'),
            route('admin.reports.invoices'),
            route('admin.reports.reminders'),
        ] as $route) {
            $this->actingAs($owner)
                ->withSession(['current_business_id' => $business->id])
                ->get($route)
                ->assertOk()
                ->assertSee('Export');
        }
    }

    public function test_booking_report_filters_status_with_tenant_scoped_results(): void
    {
        $this->seed();
        [$owner, $business] = $this->ownerAndBusiness();

        $this->actingAs($owner)
            ->withSession(['current_business_id' => $business->id])
            ->get(route('admin.reports.bookings', ['status' => AppointmentStatus::Cancelled->value]))
            ->assertOk()
            ->assertSee('BK-1004')
            ->assertDontSee('BK-1001');
    }

    public function test_reports_do_not_leak_other_business_data(): void
    {
        $this->seed();
        [$owner, $business] = $this->ownerAndBusiness();
        $otherBusiness = Business::query()->where('slug', 'prime-dental-clinic')->firstOrFail();
        $service = $otherBusiness->services()->firstOrFail();
        $staff = $otherBusiness->staffProfiles()->firstOrFail();
        $customer = Customer::query()->create([
            'business_id' => $otherBusiness->id,
            'name' => 'Other Tenant Only',
            'email' => 'other-tenant-only@example.test',
            'phone' => '(555) 000-9999',
            'status' => Customer::STATUS_ACTIVE,
            'source' => 'Test',
        ]);

        Appointment::query()->create([
            'business_id' => $otherBusiness->id,
            'customer_id' => $customer->id,
            'service_id' => $service->id,
            'staff_profile_id' => $staff->id,
            'booking_number' => 'BK-OTHER-TENANT',
            'status' => AppointmentStatus::Confirmed->value,
            'starts_at' => now()->setTime(15, 0),
            'ends_at' => now()->setTime(16, 0),
            'duration_minutes' => 60,
            'price' => 99,
            'payment_status' => 'unpaid',
            'cancel_token' => Str::uuid()->toString(),
            'reschedule_token' => Str::uuid()->toString(),
        ]);

        $this->actingAs($owner)
            ->withSession(['current_business_id' => $business->id])
            ->get(route('admin.reports.bookings', ['range' => 'this_month']))
            ->assertOk()
            ->assertDontSee('Other Tenant Only')
            ->assertDontSee('BK-OTHER-TENANT');
    }

    public function test_report_filters_include_custom_date_staff_service_and_status(): void
    {
        $this->seed();
        [$owner, $business] = $this->ownerAndBusiness();
        $appointment = $business->appointments()->with(['staffProfile', 'service'])->where('status', AppointmentStatus::Confirmed->value)->firstOrFail();

        $this->actingAs($owner)
            ->withSession(['current_business_id' => $business->id])
            ->get(route('admin.reports.bookings', [
                'range' => 'custom',
                'start_date' => $appointment->starts_at->copy()->subDay()->toDateString(),
                'end_date' => $appointment->starts_at->copy()->addDay()->toDateString(),
                'staff_id' => $appointment->staff_profile_id,
                'service_id' => $appointment->service_id,
                'status' => AppointmentStatus::Confirmed->value,
            ]))
            ->assertOk()
            ->assertSee($appointment->booking_number)
            ->assertSee($appointment->staffProfile->name)
            ->assertSee($appointment->service->name);
    }

    public function test_non_business_roles_cannot_access_business_reports(): void
    {
        $admin = User::factory()->create(['role' => UserRole::SuperAdmin->value]);

        $this->actingAs($admin)
            ->get(route('admin.reports.index'))
            ->assertForbidden();
    }

    private function ownerAndBusiness(): array
    {
        return [
            User::query()->where('email', 'owner@booklio.test')->firstOrFail(),
            Business::query()->where('slug', 'glow-beauty-salon')->firstOrFail(),
        ];
    }
}
