<?php

declare(strict_types=1);

use App\Models\Invoice;
use App\Models\Plan;
use App\Models\Service;
use App\Models\User;
use Database\Seeders\RoleAndPermissionSeeder;

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

describe('Dashboard', function (): void {
    it('allows a customer to view the dashboard', function (): void {
        $customer = User::factory()->customer()->create();

        $this->actingAs($customer)
            ->get($this->accountUrl.'/dashboard')
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('Dashboard')
                ->has('activeServicesCount')
                ->has('activeSubscriptionsCount')
                ->has('pendingInvoicesAmount')
                ->has('latestInvoices')
            );
    });

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

    it('shows correct active services count', function (): void {
        $customer = User::factory()->customer()->create();
        Service::factory()->count(3)->create(['user_id' => $customer->id, 'status' => 'active']);
        Service::factory()->create(['user_id' => $customer->id, 'status' => 'suspended']);

        $this->actingAs($customer)
            ->get($this->accountUrl.'/dashboard')
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('Dashboard')
                ->where('activeServicesCount', 3)
            );
    });

    it('shows correct pending invoices amount', function (): void {
        $customer = User::factory()->customer()->create();
        Invoice::factory()->create(['user_id' => $customer->id, 'status' => 'pending', 'total' => 50.00]);
        Invoice::factory()->create(['user_id' => $customer->id, 'status' => 'overdue', 'total' => 25.50]);
        Invoice::factory()->create(['user_id' => $customer->id, 'status' => 'paid', 'total' => 100.00]);

        $this->actingAs($customer)
            ->get($this->accountUrl.'/dashboard')
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('Dashboard')
                ->where('pendingInvoicesAmount', '75.50')
            );
    });
});

describe('Profile', function (): void {
    it('allows a customer to view their profile', function (): void {
        $customer = User::factory()->customer()->create();

        $this->actingAs($customer)
            ->get($this->accountUrl.'/profile')
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('Profile/Show')
                ->has('user')
                ->has('twoFactorEnabled')
            );
    });

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

        $this->actingAs($customer)
            ->put($this->accountUrl.'/profile', [
                'first_name' => 'Jane',
                'last_name' => 'Smith',
                'phone' => '+1234567890',
                'company' => 'Acme Inc',
            ])
            ->assertRedirect()
            ->assertSessionHas('success', 'Profile updated successfully.');

        $customer->refresh();
        expect($customer->name)->toBe('Jane Smith');
        expect($customer->phone)->toBe('+1234567890');
        expect($customer->company)->toBe('Acme Inc');
    });

    it('validates profile update requires first and last name', function (): void {
        $customer = User::factory()->customer()->create();

        $this->actingAs($customer)
            ->put($this->accountUrl.'/profile', [
                'first_name' => '',
                'last_name' => '',
            ])
            ->assertSessionHasErrors(['first_name', 'last_name']);
    });

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

        $this->actingAs($customer)
            ->put($this->accountUrl.'/profile/password', [
                'current_password' => 'password',
                'password' => 'NewSecurePass1!',
                'password_confirmation' => 'NewSecurePass1!',
            ])
            ->assertRedirect()
            ->assertSessionHas('success', 'Password updated successfully.');
    });

    it('rejects password update with wrong current password', function (): void {
        $customer = User::factory()->customer()->create();

        $this->actingAs($customer)
            ->put($this->accountUrl.'/profile/password', [
                'current_password' => 'wrong-password',
                'password' => 'NewSecurePass1!',
                'password_confirmation' => 'NewSecurePass1!',
            ])
            ->assertSessionHasErrors('current_password');
    });

    it('rejects password update when confirmation does not match', function (): void {
        $customer = User::factory()->customer()->create();

        $this->actingAs($customer)
            ->put($this->accountUrl.'/profile/password', [
                'current_password' => 'password',
                'password' => 'NewSecurePass1!',
                'password_confirmation' => 'DifferentPass2!',
            ])
            ->assertSessionHasErrors('password');
    });
});

describe('Plans', function (): void {
    it('displays active plans to a customer', function (): void {
        $customer = User::factory()->customer()->create();
        Plan::factory()->count(3)->create(['status' => 'active']);
        Plan::factory()->create(['status' => 'inactive']);

        $this->actingAs($customer)
            ->get($this->accountUrl.'/plans')
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('Plans/Index')
                ->has('plansByType')
            );
    });

    it('displays a single plan detail page', function (): void {
        $customer = User::factory()->customer()->create();
        $plan = Plan::factory()->create(['status' => 'active']);

        $this->actingAs($customer)
            ->get($this->accountUrl.'/plans/'.$plan->id)
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('Plans/Show')
                ->has('plan')
                ->where('plan.id', $plan->id)
            );
    });
});

describe('Services', function (): void {
    it('displays only the customers own services', function (): void {
        $customer = User::factory()->customer()->create();
        $otherUser = User::factory()->customer()->create();

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

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

    it('allows a customer to view their own service detail', function (): void {
        $customer = User::factory()->customer()->create();
        $service = Service::factory()->create(['user_id' => $customer->id]);

        $this->actingAs($customer)
            ->get($this->accountUrl.'/services/'.$service->id)
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('Services/Show')
                ->has('service')
                ->where('service.id', $service->id)
            );
    });

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

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

describe('Subscriptions', function (): void {
    it('displays the subscriptions list page', function (): void {
        $customer = User::factory()->customer()->create();

        $this->actingAs($customer)
            ->get($this->accountUrl.'/subscriptions')
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('Subscriptions/Index')
                ->has('subscriptions')
            );
    });

    it('requires authentication to view subscriptions', function (): void {
        $this->get($this->accountUrl.'/subscriptions')
            ->assertRedirect();
    });
});

describe('Billing', function (): void {
    it('displays the billing index page', function (): void {
        $customer = User::factory()->customer()->create();

        $this->actingAs($customer)
            ->get($this->accountUrl.'/billing')
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('Billing/Index')
                ->has('paymentMethods')
                ->has('invoices')
                ->has('transactions')
            );
    });

    it('displays the invoices page with customer invoices', function (): void {
        $customer = User::factory()->customer()->create();
        Invoice::factory()->count(3)->create(['user_id' => $customer->id]);

        $this->actingAs($customer)
            ->get($this->accountUrl.'/billing/invoices')
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('Billing/Invoices')
                ->has('invoices.data', 3)
            );
    });

    it('displays the transactions page', function (): void {
        $customer = User::factory()->customer()->create();

        $this->actingAs($customer)
            ->get($this->accountUrl.'/billing/transactions')
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('Billing/Transactions')
                ->has('transactions')
            );
    });

    it('requires authentication to view billing', function (): void {
        $this->get($this->accountUrl.'/billing')
            ->assertRedirect();
    });
});
