<?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\Service;
use App\Models\StaffBreak;
use App\Models\StaffProfile;
use App\Models\User;
use App\Models\WorkingHour;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class StaffCrudTest extends TestCase
{
    use RefreshDatabase;

    public function test_owner_can_filter_staff_from_backend_queries(): void
    {
        [$owner, $business] = $this->ownerWithBusiness();
        $hair = $this->service($business, ['name' => 'Hair Cut & Style']);
        $facial = $this->service($business, ['name' => 'Facial Treatment']);
        $emma = $this->staff($business, ['name' => 'Emma Wilson', 'role' => 'Senior Stylist', 'availability_status' => StaffProfile::AVAILABILITY_AVAILABLE]);
        $sophia = $this->staff($business, ['name' => 'Sophia Davis', 'role' => 'Skin Expert', 'availability_status' => StaffProfile::AVAILABILITY_BUSY]);
        $emma->services()->attach($hair->id, ['business_id' => $business->id]);
        $sophia->services()->attach($facial->id, ['business_id' => $business->id]);

        $this->actingAs($owner)
            ->get('/staff?q=emma&service_id='.$hair->id.'&status=available')
            ->assertOk()
            ->assertSee('Emma Wilson')
            ->assertDontSee('Skin Expert');
    }

    public function test_owner_can_create_staff_profile_with_services_and_default_hours(): void
    {
        [$owner, $business] = $this->ownerWithBusiness();
        $service = $this->service($business);

        $response = $this->actingAs($owner)->post('/staff', [
            'name' => 'Nora Evans',
            'role' => 'Service Expert',
            'email' => 'nora@example.com',
            'phone' => '(555) 111-2222',
            'availability_status' => StaffProfile::AVAILABILITY_AVAILABLE,
            'calendar_color' => '#10B981',
            'bio' => 'Friendly provider for premium appointments.',
            'service_ids' => [$service->id],
        ]);

        $staff = StaffProfile::query()->where('email', 'nora@example.com')->first();

        $response->assertRedirect(route('admin.staff.show', $staff));
        $this->assertDatabaseHas('staff_profiles', [
            'business_id' => $business->id,
            'name' => 'Nora Evans',
            'availability_status' => StaffProfile::AVAILABILITY_AVAILABLE,
        ]);
        $this->assertDatabaseHas('staff_services', [
            'business_id' => $business->id,
            'staff_profile_id' => $staff->id,
            'service_id' => $service->id,
        ]);
        $this->assertSame(7, WorkingHour::query()->where('staff_profile_id', $staff->id)->count());
    }

    public function test_owner_can_update_staff_profile(): void
    {
        [$owner, $business] = $this->ownerWithBusiness();
        $service = $this->service($business, ['name' => 'Beard Trim']);
        $staff = $this->staff($business, ['name' => 'James Smith']);

        $this->actingAs($owner)->put('/staff/'.$staff->id, [
            'name' => 'James A. Smith',
            'role' => 'Senior Barber',
            'email' => 'james@example.com',
            'phone' => '(555) 333-4444',
            'availability_status' => StaffProfile::AVAILABILITY_BUSY,
            'calendar_color' => '#F59E0B',
            'bio' => 'Updated staff bio.',
            'service_ids' => [$service->id],
        ])->assertRedirect(route('admin.staff.show', $staff));

        $this->assertDatabaseHas('staff_profiles', [
            'id' => $staff->id,
            'name' => 'James A. Smith',
            'role' => 'Senior Barber',
            'availability_status' => StaffProfile::AVAILABILITY_BUSY,
        ]);
        $this->assertDatabaseHas('staff_services', [
            'staff_profile_id' => $staff->id,
            'service_id' => $service->id,
        ]);
    }

    public function test_owner_can_update_working_hours_and_breaks(): void
    {
        [$owner, $business] = $this->ownerWithBusiness();
        $staff = $this->staff($business);

        $hours = collect(range(0, 6))->map(fn (int $day) => [
            'day_of_week' => $day,
            'enabled' => $day === 0 ? 0 : 1,
            'starts_at' => $day === 0 ? null : '10:00',
            'ends_at' => $day === 0 ? null : '18:00',
            'break_start' => $day === 1 ? '13:00' : null,
            'break_end' => $day === 1 ? '13:30' : null,
        ])->all();

        $this->actingAs($owner)
            ->put('/staff/'.$staff->id.'/working-hours', ['hours' => $hours])
            ->assertRedirect(route('admin.staff.working-hours', $staff));

        $this->assertDatabaseHas('working_hours', [
            'business_id' => $business->id,
            'staff_profile_id' => $staff->id,
            'day_of_week' => 1,
            'starts_at' => '10:00',
            'ends_at' => '18:00',
            'is_closed' => false,
        ]);
        $this->assertDatabaseHas('staff_breaks', [
            'business_id' => $business->id,
            'staff_profile_id' => $staff->id,
            'day_of_week' => 1,
            'starts_at' => '13:00',
            'ends_at' => '13:30',
            'is_recurring' => true,
        ]);
    }

    public function test_owner_can_view_stats_and_delete_staff_profile(): void
    {
        [$owner, $business] = $this->ownerWithBusiness();
        $service = $this->service($business);
        $staff = $this->staff($business, ['name' => 'Olivia Brown']);
        $customer = Customer::query()->create([
            'business_id' => $business->id,
            'name' => 'Jessica Miller',
        ]);
        Appointment::query()->create([
            'business_id' => $business->id,
            'customer_id' => $customer->id,
            'service_id' => $service->id,
            'staff_profile_id' => $staff->id,
            'booking_number' => 'BK-1001',
            'status' => AppointmentStatus::Completed->value,
            'starts_at' => now()->setTime(10, 0),
            'ends_at' => now()->setTime(11, 0),
            'duration_minutes' => 60,
            'price' => 65,
        ]);

        $this->actingAs($owner)
            ->get('/staff/'.$staff->id)
            ->assertOk()
            ->assertSee('Olivia Brown')
            ->assertSee('Jessica Miller')
            ->assertSee('$65.00');

        $this->actingAs($owner)
            ->delete('/staff/'.$staff->id)
            ->assertRedirect('/staff');

        $this->assertSoftDeleted('staff_profiles', ['id' => $staff->id]);
    }

    public function test_owner_cannot_access_another_business_staff_profile(): void
    {
        [$owner] = $this->ownerWithBusiness();
        [, $otherBusiness] = $this->ownerWithBusiness('other-owner@booklio.test');
        $otherStaff = $this->staff($otherBusiness, ['name' => 'Private Staff']);

        $this->actingAs($owner)
            ->get('/staff/'.$otherStaff->id)
            ->assertNotFound();
    }

    private function ownerWithBusiness(string $email = 'owner@booklio.test'): array
    {
        $owner = User::factory()->create([
            'email' => $email,
            'role' => UserRole::BusinessOwner->value,
        ]);
        $business = Business::factory()->create([
            'owner_id' => $owner->id,
            'status' => 'active',
        ]);

        return [$owner, $business];
    }

    private function staff(Business $business, array $overrides = []): StaffProfile
    {
        return StaffProfile::query()->create(array_merge([
            'business_id' => $business->id,
            'name' => 'Emma Wilson',
            'email' => 'emma@example.com',
            'phone' => '(555) 123-4567',
            'role' => 'Senior Stylist',
            'status' => StaffProfile::STATUS_ACTIVE,
            'availability_status' => StaffProfile::AVAILABILITY_AVAILABLE,
            'color' => '#2563EB',
        ], $overrides));
    }

    private function service(Business $business, array $overrides = []): Service
    {
        $name = $overrides['name'] ?? 'Hair Cut & Style';

        return Service::query()->create(array_merge([
            'business_id' => $business->id,
            'name' => $name,
            'slug' => Service::uniqueSlug($business->id, $name),
            'category' => 'Hair Services',
            'price' => 65,
            'duration_minutes' => 60,
            'description' => 'A polished service description.',
            'buffer_before_minutes' => 10,
            'buffer_after_minutes' => 10,
            'status' => Service::STATUS_ACTIVE,
        ], $overrides));
    }
}
