<?php

declare(strict_types=1);

use App\Models\Plan;
use App\Models\PlanConfigGroup;
use App\Models\PlanConfigOption;
use App\Models\PlanConfigValue;
use App\Models\SubscriptionConfigSelection;
use App\Models\User;
use Database\Seeders\RoleAndPermissionSeeder;
use Laravel\Cashier\Subscription;

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

describe('PlanConfigGroup Model', function (): void {
    it('creates a preset group with options and values', function (): void {
        $group = PlanConfigGroup::factory()->create(['mode' => 'preset']);
        $option = PlanConfigOption::factory()->create([
            'group_id' => $group->id,
            'type' => 'dropdown',
            'name' => 'RAM',
        ]);
        $value = PlanConfigValue::factory()->withPrice(15.00)->create([
            'option_id' => $option->id,
            'label' => '64 GB',
        ]);

        expect($group->options)->toHaveCount(1);
        expect($option->values)->toHaveCount(1);
        expect($value->getPriceForCycle('monthly'))->toBe(15.0);
    });

    it('scopes preset and build_your_own groups', function (): void {
        PlanConfigGroup::factory()->create(['mode' => 'preset']);
        PlanConfigGroup::factory()->buildYourOwn('vps')->create();
        PlanConfigGroup::factory()->buildYourOwn('game')->create();

        expect(PlanConfigGroup::preset()->count())->toBe(1);
        expect(PlanConfigGroup::buildYourOwn()->count())->toBe(2);
        expect(PlanConfigGroup::buildYourOwn()->forServiceType('vps')->count())->toBe(1);
    });

    it('attaches to plans via pivot', function (): void {
        $group = PlanConfigGroup::factory()->create();
        $plan = Plan::factory()->create();
        $group->plans()->attach($plan->id);

        expect($group->plans)->toHaveCount(1);
        expect($plan->configGroups)->toHaveCount(1);
    });

    it('soft deletes and restores', function (): void {
        $group = PlanConfigGroup::factory()->create();
        $group->delete();

        expect(PlanConfigGroup::count())->toBe(0);
        expect(PlanConfigGroup::withTrashed()->count())->toBe(1);

        $group->restore();
        expect(PlanConfigGroup::count())->toBe(1);
    });

    it('filters active groups', function (): void {
        PlanConfigGroup::factory()->create(['is_active' => true]);
        PlanConfigGroup::factory()->inactive()->create();

        expect(PlanConfigGroup::active()->count())->toBe(1);
    });
});

describe('PlanConfigOption Model', function (): void {
    it('calculates slider price correctly', function (): void {
        $option = PlanConfigOption::factory()->slider(2.00, 0.003)->create([
            'name' => 'CPU Cores',
            'unit_label' => 'cores',
        ]);

        expect($option->calculatePrice(4, 'monthly'))->toBe(8.0);
        expect($option->getHourlyPrice(4))->toBe(0.012);
        expect($option->isSlider())->toBeTrue();
    });

    it('calculates price for different billing cycles', function (): void {
        $option = PlanConfigOption::factory()->create([
            'type' => 'quantity',
            'monthly_price' => 3.00,
            'quarterly_price' => 8.55,
            'semi_annual_price' => 16.20,
            'annual_price' => 30.60,
        ]);

        expect($option->calculatePrice(2, 'monthly'))->toBe(6.0);
        expect($option->calculatePrice(2, 'quarterly'))->toBe(17.1);
        expect($option->calculatePrice(2, 'annual'))->toBe(61.2);
    });

    it('identifies option types correctly', function (): void {
        $dropdown = PlanConfigOption::factory()->create(['type' => 'dropdown']);
        $slider = PlanConfigOption::factory()->slider(1.00)->create();
        $checkbox = PlanConfigOption::factory()->checkbox()->create();
        $text = PlanConfigOption::factory()->create(['type' => 'text']);

        expect($dropdown->isDropdown())->toBeTrue();
        expect($dropdown->isSlider())->toBeFalse();
        expect($slider->isSlider())->toBeTrue();
        expect($checkbox->isCheckbox())->toBeTrue();
        expect($text->isText())->toBeTrue();
    });

    it('filters active options', function (): void {
        $group = PlanConfigGroup::factory()->create();
        PlanConfigOption::factory()->create(['group_id' => $group->id, 'is_active' => true]);
        PlanConfigOption::factory()->create(['group_id' => $group->id, 'is_active' => false]);

        expect(PlanConfigOption::active()->count())->toBe(1);
    });
});

describe('PlanConfigValue Model', function (): void {
    it('returns price for each billing cycle', function (): void {
        $value = PlanConfigValue::factory()->create([
            'monthly_price' => 15.00,
            'quarterly_price' => 42.75,
            'semi_annual_price' => 81.00,
            'annual_price' => 153.00,
        ]);

        expect($value->getPriceForCycle('monthly'))->toBe(15.0);
        expect($value->getPriceForCycle('quarterly'))->toBe(42.75);
        expect($value->getPriceForCycle('semi_annual'))->toBe(81.0);
        expect($value->getPriceForCycle('annual'))->toBe(153.0);
    });
});

describe('Plan Model Updates', function (): void {
    it('treats internal status as available', function (): void {
        $active = Plan::factory()->create(['status' => 'active']);
        $internal = Plan::factory()->create(['status' => 'internal']);
        $hidden = Plan::factory()->create(['status' => 'hidden']);

        expect($active->isAvailable())->toBeTrue();
        expect($internal->isAvailable())->toBeTrue();
        expect($hidden->isAvailable())->toBeFalse();
    });

    it('excludes internal and hidden from public scope', function (): void {
        Plan::factory()->create(['status' => 'active']);
        Plan::factory()->create(['status' => 'internal']);
        Plan::factory()->create(['status' => 'hidden']);

        expect(Plan::public()->count())->toBe(1);
    });
});

describe('Admin Config Group CRUD', function (): void {
    it('lists config groups', function (): void {
        $admin = User::factory()->admin()->create();
        PlanConfigGroup::factory()->count(3)->create();

        $this->actingAs($admin)
            ->get($this->adminUrl.'/config-groups')
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('Admin/ConfigGroups/Index')
                ->has('configGroups', 3)
                ->has('filters')
            );
    });

    it('creates preset config group with options and values', function (): void {
        $admin = User::factory()->admin()->create();
        $plan = Plan::factory()->create(['status' => 'active']);

        $this->actingAs($admin)
            ->post($this->adminUrl.'/config-groups', [
                'name' => 'VPS RAM Options',
                'description' => 'Choose your RAM',
                'mode' => 'preset',
                'service_type' => null,
                'is_active' => true,
                'plan_ids' => [$plan->id],
                'options' => [
                    [
                        'name' => 'RAM',
                        'description' => 'Memory allocation',
                        'type' => 'dropdown',
                        'provisioning_key' => 'ram',
                        'required' => true,
                        'is_active' => true,
                        'values' => [
                            [
                                'label' => '8 GB',
                                'value' => '8',
                                'monthly_price' => 10.00,
                                'quarterly_price' => 28.50,
                                'semi_annual_price' => 54.00,
                                'annual_price' => 102.00,
                                'is_default' => true,
                            ],
                            [
                                'label' => '16 GB',
                                'value' => '16',
                                'monthly_price' => 20.00,
                                'quarterly_price' => 57.00,
                                'semi_annual_price' => 108.00,
                                'annual_price' => 204.00,
                                'is_default' => false,
                            ],
                        ],
                    ],
                ],
            ])
            ->assertRedirect();

        $group = PlanConfigGroup::query()->where('name', 'VPS RAM Options')->first();
        expect($group)->not->toBeNull();
        expect($group->mode)->toBe('preset');
        expect($group->plans)->toHaveCount(1);
        expect($group->plans->first()->id)->toBe($plan->id);
        expect($group->options)->toHaveCount(1);
        expect($group->options->first()->name)->toBe('RAM');
        expect($group->options->first()->provisioning_key)->toBe('ram');
        expect($group->options->first()->values)->toHaveCount(2);
        expect($group->options->first()->values->first()->label)->toBe('8 GB');
    });

    it('creates BYO config group with slider options', function (): void {
        $admin = User::factory()->admin()->create();

        $this->actingAs($admin)
            ->post($this->adminUrl.'/config-groups', [
                'name' => 'Custom VPS Builder',
                'mode' => 'build_your_own',
                'service_type' => 'vps',
                'is_active' => true,
                'options' => [
                    [
                        'name' => 'CPU Cores',
                        'type' => 'slider',
                        'provisioning_key' => 'cpu',
                        'required' => true,
                        'is_active' => true,
                        'min_qty' => 1,
                        'max_qty' => 32,
                        'step' => 1,
                        'unit_label' => 'cores',
                        'monthly_price' => 5.00,
                        'hourly_price' => 0.0075,
                    ],
                ],
            ])
            ->assertRedirect();

        $group = PlanConfigGroup::query()->where('name', 'Custom VPS Builder')->first();
        expect($group)->not->toBeNull();
        expect($group->mode)->toBe('build_your_own');
        expect($group->service_type)->toBe('vps');
        expect($group->options->first()->provisioning_key)->toBe('cpu');
        expect($group->options->first()->type)->toBe('slider');
        expect($group->options->first()->min_qty)->toBe(1);
        expect($group->options->first()->max_qty)->toBe(32);
    });

    it('updates a config group', function (): void {
        $admin = User::factory()->admin()->create();
        $group = PlanConfigGroup::factory()->create(['name' => 'Old Name']);
        $option = PlanConfigOption::factory()->create([
            'group_id' => $group->id,
            'type' => 'dropdown',
            'name' => 'RAM',
        ]);

        $this->actingAs($admin)
            ->put($this->adminUrl.'/config-groups/'.$group->id, [
                'name' => 'Updated Name',
                'mode' => $group->mode,
                'is_active' => true,
                'options' => [
                    [
                        'id' => $option->id,
                        'name' => 'RAM',
                        'type' => 'dropdown',
                        'required' => false,
                        'is_active' => true,
                    ],
                ],
            ])
            ->assertRedirect();

        $group->refresh();
        expect($group->name)->toBe('Updated Name');
    });

    it('archives config group with existing selections', function (): void {
        $admin = User::factory()->admin()->create();
        $customer = User::factory()->customer()->create();
        $group = PlanConfigGroup::factory()->create(['is_active' => true]);
        $option = PlanConfigOption::factory()->create(['group_id' => $group->id]);

        $subscription = Subscription::factory()->create(['user_id' => $customer->id]);

        SubscriptionConfigSelection::query()->create([
            'subscription_id' => $subscription->id,
            'option_id' => $option->id,
            'value_id' => null,
            'quantity' => 4,
            'locked_price' => 20.00,
            'billing_cycle' => 'monthly',
            'is_custom_build' => false,
        ]);

        $this->actingAs($admin)
            ->delete($this->adminUrl.'/config-groups/'.$group->id)
            ->assertRedirect();

        // Should soft-delete and deactivate, not hard delete
        expect(PlanConfigGroup::query()->find($group->id))->toBeNull();
        $trashedGroup = PlanConfigGroup::withTrashed()->find($group->id);
        expect($trashedGroup)->not->toBeNull();
        expect($trashedGroup->is_active)->toBeFalse();
    });

    it('prevents customer from accessing config groups', function (): void {
        $customer = User::factory()->customer()->create();

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

    it('validates required fields', function (): void {
        $admin = User::factory()->admin()->create();

        $this->actingAs($admin)
            ->post($this->adminUrl.'/config-groups', [])
            ->assertSessionHasErrors(['name', 'mode', 'options']);
    });
});
