<?php

declare(strict_types=1);

use App\Models\SupportTicket;
use App\Models\TicketReply;
use App\Models\User;
use Database\Seeders\RoleAndPermissionSeeder;

beforeEach(function (): void {
    $this->seed(RoleAndPermissionSeeder::class);
    $this->accountUrl = 'http://'.config('app.domains.account');
    $this->adminUrl = 'http://'.config('app.domains.admin');
});

// ---------------------------------------------------------------------------
// Customer Ticket Management
// ---------------------------------------------------------------------------
describe('Customer Ticket List', function (): void {
    it('allows a customer to view their ticket list', function (): void {
        $customer = User::factory()->customer()->create();
        SupportTicket::factory()->count(3)->create(['user_id' => $customer->id]);

        $this->actingAs($customer)
            ->get($this->accountUrl.'/tickets')
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('Tickets/Index')
                ->has('tickets.data', 3)
            );
    });

    it('customer cannot see other users tickets', function (): void {
        $customer = User::factory()->customer()->create();
        $otherUser = User::factory()->customer()->create();

        SupportTicket::factory()->count(2)->create(['user_id' => $customer->id]);
        SupportTicket::factory()->count(3)->create(['user_id' => $otherUser->id]);

        $this->actingAs($customer)
            ->get($this->accountUrl.'/tickets')
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('Tickets/Index')
                ->has('tickets.data', 2)
            );
    });

    it('redirects guests to login when accessing ticket list', function (): void {
        $this->get($this->accountUrl.'/tickets')
            ->assertRedirect();
    });
});

describe('Customer Ticket Creation', function (): void {
    it('displays the create ticket form', function (): void {
        $customer = User::factory()->customer()->create();

        $this->actingAs($customer)
            ->get($this->accountUrl.'/tickets/create')
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('Tickets/Create')
            );
    });

    it('allows a customer to create a ticket', function (): void {
        $customer = User::factory()->customer()->create();

        $this->actingAs($customer)
            ->post($this->accountUrl.'/tickets', [
                'subject' => 'Unable to access VPS',
                'department' => 'technical',
                'priority' => 'high',
                'message' => 'I cannot SSH into my VPS server. Please help.',
            ])
            ->assertRedirect();

        $this->assertDatabaseHas('support_tickets', [
            'user_id' => $customer->id,
            'subject' => 'Unable to access VPS',
            'department' => 'technical',
            'priority' => 'high',
            'status' => 'open',
        ]);

        $ticket = SupportTicket::where('user_id', $customer->id)->first();
        $this->assertDatabaseHas('ticket_replies', [
            'ticket_id' => $ticket->id,
            'user_id' => $customer->id,
            'body' => 'I cannot SSH into my VPS server. Please help.',
            'is_staff_reply' => false,
        ]);
    });

    it('validates required fields when creating a ticket', function (): void {
        $customer = User::factory()->customer()->create();

        $this->actingAs($customer)
            ->post($this->accountUrl.'/tickets', [])
            ->assertSessionHasErrors(['subject', 'department', 'priority', 'message']);
    });

    it('requires authentication to create a ticket', function (): void {
        $this->get($this->accountUrl.'/tickets/create')
            ->assertRedirect();
    });
});

describe('Customer Ticket Detail', function (): void {
    it('allows a customer to view their own ticket detail', function (): void {
        $customer = User::factory()->customer()->create();
        $ticket = SupportTicket::factory()->create(['user_id' => $customer->id]);
        TicketReply::factory()->count(2)->create([
            'ticket_id' => $ticket->id,
            'user_id' => $customer->id,
        ]);

        $this->actingAs($customer)
            ->get($this->accountUrl.'/tickets/'.$ticket->id)
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('Tickets/Show')
                ->has('ticket')
                ->has('ticket.replies', 2)
                ->where('ticket.id', $ticket->id)
            );
    });

    it('forbids a customer from viewing another users ticket', function (): void {
        $customer = User::factory()->customer()->create();
        $otherUser = User::factory()->customer()->create();
        $ticket = SupportTicket::factory()->create(['user_id' => $otherUser->id]);

        $this->actingAs($customer)
            ->get($this->accountUrl.'/tickets/'.$ticket->id)
            ->assertForbidden();
    });
});

describe('Customer Ticket Reply', function (): void {
    it('allows a customer to reply to their open ticket', function (): void {
        $customer = User::factory()->customer()->create();
        $ticket = SupportTicket::factory()->open()->create(['user_id' => $customer->id]);

        $this->actingAs($customer)
            ->post($this->accountUrl.'/tickets/'.$ticket->id.'/reply', [
                'body' => 'Here is additional information about my issue.',
            ])
            ->assertRedirect();

        $this->assertDatabaseHas('ticket_replies', [
            'ticket_id' => $ticket->id,
            'user_id' => $customer->id,
            'body' => 'Here is additional information about my issue.',
            'is_staff_reply' => false,
        ]);

        expect($ticket->fresh()->last_reply_at)->not->toBeNull();
    });

    it('customer cannot reply to a closed ticket', function (): void {
        $customer = User::factory()->customer()->create();
        $ticket = SupportTicket::factory()->closed()->create(['user_id' => $customer->id]);

        $this->actingAs($customer)
            ->post($this->accountUrl.'/tickets/'.$ticket->id.'/reply', [
                'body' => 'Trying to reply to closed ticket.',
            ])
            ->assertForbidden();
    });

    it('customer cannot reply to another users ticket', function (): void {
        $customer = User::factory()->customer()->create();
        $otherUser = User::factory()->customer()->create();
        $ticket = SupportTicket::factory()->open()->create(['user_id' => $otherUser->id]);

        $this->actingAs($customer)
            ->post($this->accountUrl.'/tickets/'.$ticket->id.'/reply', [
                'body' => 'Unauthorized reply attempt.',
            ])
            ->assertForbidden();
    });

    it('validates reply body is required', function (): void {
        $customer = User::factory()->customer()->create();
        $ticket = SupportTicket::factory()->open()->create(['user_id' => $customer->id]);

        $this->actingAs($customer)
            ->post($this->accountUrl.'/tickets/'.$ticket->id.'/reply', [])
            ->assertSessionHasErrors(['body']);
    });
});

describe('Customer Ticket Close', function (): void {
    it('allows a customer to close their ticket', function (): void {
        $customer = User::factory()->customer()->create();
        $ticket = SupportTicket::factory()->open()->create(['user_id' => $customer->id]);

        $this->actingAs($customer)
            ->post($this->accountUrl.'/tickets/'.$ticket->id.'/close')
            ->assertRedirect();

        expect($ticket->fresh()->status)->toBe('closed');
    });

    it('customer cannot close another users ticket', function (): void {
        $customer = User::factory()->customer()->create();
        $otherUser = User::factory()->customer()->create();
        $ticket = SupportTicket::factory()->open()->create(['user_id' => $otherUser->id]);

        $this->actingAs($customer)
            ->post($this->accountUrl.'/tickets/'.$ticket->id.'/close')
            ->assertForbidden();
    });
});

// ---------------------------------------------------------------------------
// Admin Ticket Management
// ---------------------------------------------------------------------------
describe('Admin Ticket List', function (): void {
    it('allows admin to view all tickets', function (): void {
        $admin = User::factory()->admin()->create();
        $customer1 = User::factory()->customer()->create();
        $customer2 = User::factory()->customer()->create();

        SupportTicket::factory()->count(2)->create(['user_id' => $customer1->id]);
        SupportTicket::factory()->count(3)->create(['user_id' => $customer2->id]);

        $this->actingAs($admin)
            ->get($this->adminUrl.'/tickets')
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('Admin/Tickets/Index')
                ->has('tickets.data', 5)
                ->has('filters')
            );
    });

    it('allows admin to filter tickets by status', function (): void {
        $admin = User::factory()->admin()->create();
        $customer = User::factory()->customer()->create();

        SupportTicket::factory()->count(2)->create([
            'user_id' => $customer->id,
            'status' => 'open',
        ]);
        SupportTicket::factory()->count(3)->create([
            'user_id' => $customer->id,
            'status' => 'closed',
        ]);

        $this->actingAs($admin)
            ->get($this->adminUrl.'/tickets?status=open')
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('Admin/Tickets/Index')
                ->has('tickets.data', 2)
            );
    });

    it('allows admin to filter tickets by priority', function (): void {
        $admin = User::factory()->admin()->create();
        $customer = User::factory()->customer()->create();

        SupportTicket::factory()->count(1)->urgent()->create(['user_id' => $customer->id]);
        SupportTicket::factory()->count(2)->create([
            'user_id' => $customer->id,
            'priority' => 'low',
        ]);

        $this->actingAs($admin)
            ->get($this->adminUrl.'/tickets?priority=urgent')
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('Admin/Tickets/Index')
                ->has('tickets.data', 1)
            );
    });

    it('allows admin to filter tickets by department', function (): void {
        $admin = User::factory()->admin()->create();
        $customer = User::factory()->customer()->create();

        SupportTicket::factory()->count(2)->create([
            'user_id' => $customer->id,
            'department' => 'billing',
        ]);
        SupportTicket::factory()->count(3)->create([
            'user_id' => $customer->id,
            'department' => 'technical',
        ]);

        $this->actingAs($admin)
            ->get($this->adminUrl.'/tickets?department=billing')
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('Admin/Tickets/Index')
                ->has('tickets.data', 2)
            );
    });

    it('denies customer access to admin ticket list', function (): void {
        $customer = User::factory()->customer()->create();

        $this->actingAs($customer)
            ->get($this->adminUrl.'/tickets')
            ->assertForbidden();
    });

    it('redirects guest to login when accessing admin ticket list', function (): void {
        $this->get($this->adminUrl.'/tickets')
            ->assertRedirect();
    });
});

describe('Admin Ticket Detail', function (): void {
    it('allows admin to view any ticket', function (): void {
        $admin = User::factory()->admin()->create();
        $customer = User::factory()->customer()->create();
        $ticket = SupportTicket::factory()->create(['user_id' => $customer->id]);
        TicketReply::factory()->count(3)->create(['ticket_id' => $ticket->id]);

        $this->actingAs($admin)
            ->get($this->adminUrl.'/tickets/'.$ticket->id)
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('Admin/Tickets/Show')
                ->has('ticket')
                ->has('ticket.replies', 3)
                ->where('ticket.id', $ticket->id)
            );
    });
});

describe('Admin Ticket Reply', function (): void {
    it('allows admin to reply to a ticket as staff', function (): void {
        $admin = User::factory()->admin()->create();
        $customer = User::factory()->customer()->create();
        $ticket = SupportTicket::factory()->open()->create(['user_id' => $customer->id]);

        $this->actingAs($admin)
            ->post($this->adminUrl.'/tickets/'.$ticket->id.'/reply', [
                'body' => 'Thank you for your inquiry. We are looking into this.',
            ])
            ->assertRedirect();

        $this->assertDatabaseHas('ticket_replies', [
            'ticket_id' => $ticket->id,
            'user_id' => $admin->id,
            'body' => 'Thank you for your inquiry. We are looking into this.',
            'is_staff_reply' => true,
        ]);

        expect($ticket->fresh()->last_reply_at)->not->toBeNull();
    });

    it('admin can reply to a closed ticket', function (): void {
        $admin = User::factory()->admin()->create();
        $customer = User::factory()->customer()->create();
        $ticket = SupportTicket::factory()->closed()->create(['user_id' => $customer->id]);

        $this->actingAs($admin)
            ->post($this->adminUrl.'/tickets/'.$ticket->id.'/reply', [
                'body' => 'Additional information regarding this closed ticket.',
            ])
            ->assertRedirect();

        $this->assertDatabaseHas('ticket_replies', [
            'ticket_id' => $ticket->id,
            'user_id' => $admin->id,
            'body' => 'Additional information regarding this closed ticket.',
            'is_staff_reply' => true,
        ]);
    });

    it('validates reply body is required for admin', function (): void {
        $admin = User::factory()->admin()->create();
        $customer = User::factory()->customer()->create();
        $ticket = SupportTicket::factory()->open()->create(['user_id' => $customer->id]);

        $this->actingAs($admin)
            ->post($this->adminUrl.'/tickets/'.$ticket->id.'/reply', [])
            ->assertSessionHasErrors(['body']);
    });
});

describe('Admin Ticket Status Update', function (): void {
    it('allows admin to update ticket status', function (): void {
        $admin = User::factory()->admin()->create();
        $customer = User::factory()->customer()->create();
        $ticket = SupportTicket::factory()->open()->create(['user_id' => $customer->id]);

        $this->actingAs($admin)
            ->put($this->adminUrl.'/tickets/'.$ticket->id.'/status', [
                'status' => 'in_progress',
            ])
            ->assertRedirect();

        expect($ticket->fresh()->status)->toBe('in_progress');
    });

    it('allows admin to change ticket to closed status', function (): void {
        $admin = User::factory()->admin()->create();
        $customer = User::factory()->customer()->create();
        $ticket = SupportTicket::factory()->open()->create(['user_id' => $customer->id]);

        $this->actingAs($admin)
            ->put($this->adminUrl.'/tickets/'.$ticket->id.'/status', [
                'status' => 'closed',
            ])
            ->assertRedirect();

        expect($ticket->fresh()->status)->toBe('closed');
    });

    it('allows admin to reopen a closed ticket', function (): void {
        $admin = User::factory()->admin()->create();
        $customer = User::factory()->customer()->create();
        $ticket = SupportTicket::factory()->closed()->create(['user_id' => $customer->id]);

        $this->actingAs($admin)
            ->put($this->adminUrl.'/tickets/'.$ticket->id.'/status', [
                'status' => 'open',
            ])
            ->assertRedirect();

        expect($ticket->fresh()->status)->toBe('open');
    });

    it('validates status is required', function (): void {
        $admin = User::factory()->admin()->create();
        $customer = User::factory()->customer()->create();
        $ticket = SupportTicket::factory()->open()->create(['user_id' => $customer->id]);

        $this->actingAs($admin)
            ->put($this->adminUrl.'/tickets/'.$ticket->id.'/status', [])
            ->assertSessionHasErrors(['status']);
    });

    it('denies customer access to status update endpoint', function (): void {
        $customer = User::factory()->customer()->create();
        $ticket = SupportTicket::factory()->open()->create(['user_id' => $customer->id]);

        $this->actingAs($customer)
            ->put($this->adminUrl.'/tickets/'.$ticket->id.'/status', [
                'status' => 'closed',
            ])
            ->assertForbidden();
    });
});
