<?php

namespace Tests\Tenant;

use Mtc\MercuryDataModels\ServicePackage;
use Mtc\MercuryDataModels\VehicleMake;
use Mtc\MercuryDataModels\VehicleModel;
use Tests\TenantTestCase;
use Tests\UserForTenant;

class ServicePackageControllerTest extends TenantTestCase
{
    use UserForTenant;

    public function testListPackagesReturnsPaginatedResults()
    {
        ServicePackage::create(['name' => 'Full Service', 'type' => 'package', 'price' => 199.99]);
        ServicePackage::create(['name' => 'Oil Change', 'type' => 'add-on', 'price' => 49.99]);
        ServicePackage::create(['name' => 'MOT', 'type' => 'package', 'price' => 54.85]);

        $response = $this->actingAs($this->getUser())
            ->getJson('/api/service-bookings/packages');

        $response->assertStatus(200);
        $this->assertCount(3, $response->json('data'));
        $this->assertArrayHasKey('current_page', $response->json());
        $this->assertArrayHasKey('per_page', $response->json());
    }

    public function testListPackagesIncludesDefaultColumns()
    {
        ServicePackage::create(['name' => 'Test', 'type' => 'package']);

        $response = $this->actingAs($this->getUser())
            ->getJson('/api/service-bookings/packages');

        $response->assertStatus(200);
        $this->assertEquals(['price', 'updated'], $response->json('default_columns'));
    }

    public function testListPackagesMapsTitleFromNameAndShowsPrice()
    {
        ServicePackage::create(['name' => 'Premium Service', 'type' => 'package', 'price' => 299.00, 'description' => 'Full premium service']);

        $response = $this->actingAs($this->getUser())
            ->getJson('/api/service-bookings/packages');

        $response->assertStatus(200);
        $package = $response->json('data.0');
        $this->assertEquals('Premium Service', $package['title']);
        $this->assertEquals('Full premium service', $package['description']);
        $this->assertNotEmpty($package['metaItems']['price']);
        $this->assertNotEmpty($package['metaItems']['updated']);
    }

    public function testCreatePackageWithValidData()
    {
        $response = $this->actingAs($this->getUser())
            ->postJson('/api/service-bookings/packages', [
                'name' => 'Brake Check',
            ]);

        $response->assertStatus(201);
        $this->assertEquals(1, ServicePackage::count());
        $this->assertEquals('Brake Check', ServicePackage::first()->name);
    }

    public function testCreatePackageRequiresName()
    {
        $response = $this->actingAs($this->getUser())
            ->postJson('/api/service-bookings/packages', [
                'price' => 100,
            ]);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['name']);
        $this->assertEquals(0, ServicePackage::count());
    }

    public function testCreatePackageDefaultsTypeToPackage()
    {
        $response = $this->actingAs($this->getUser())
            ->postJson('/api/service-bookings/packages', [
                'name' => 'New Package',
            ]);

        $response->assertStatus(201);
        $this->assertEquals('package', ServicePackage::first()->type);
    }

    public function testShowPackageIncludesPackageTypes()
    {
        $package = ServicePackage::create([
            'name' => 'Test Package',
            'type' => 'package',
            'price' => 100,
        ]);

        $response = $this->actingAs($this->getUser())
            ->getJson('/api/service-bookings/packages/' . $package->id);

        $response->assertStatus(200);
        $this->assertEquals('Test Package', $response->json('name'));
        $this->assertEquals(100, $response->json('price'));

        $packageTypes = $response->json('package_types');
        $this->assertCount(2, $packageTypes);
        $this->assertEquals('package', $packageTypes[0]['id']);
        $this->assertEquals('Package', $packageTypes[0]['name']);
        $this->assertEquals('add-on', $packageTypes[1]['id']);
        $this->assertEquals('Add-on', $packageTypes[1]['name']);
    }

    public function testShowPackageIncludesMakesList()
    {
        $package = ServicePackage::create(['name' => 'Test', 'type' => 'package']);

        $response = $this->actingAs($this->getUser())
            ->getJson('/api/service-bookings/packages/' . $package->id);

        $response->assertStatus(200);
        $this->assertArrayHasKey('makes', $response->json());
    }

    public function testShowPackageIncludesModelsForSelectedMake()
    {
        $make = VehicleMake::factory()->create(['name' => 'Ford']);
        $model = VehicleModel::factory()->create(['name' => 'Focus', 'make_id' => $make->id]);
        VehicleModel::factory()->create(['name' => 'Astra']); // different make, should not appear

        $package = ServicePackage::create([
            'name' => 'Test',
            'type' => 'package',
            'applicable_make_id' => $make->id,
            'applicable_model_id' => $model->id,
        ]);

        $response = $this->actingAs($this->getUser())
            ->getJson('/api/service-bookings/packages/' . $package->id);

        $response->assertStatus(200);
        $this->assertArrayHasKey('models', $response->json());
        $modelNames = collect($response->json('models'))->pluck('name')->toArray();
        $this->assertContains('Focus', $modelNames);
        $this->assertNotContains('Astra', $modelNames);
    }

    public function testShowPackageReturnsEmptyModelsWhenNoMakeSelected()
    {
        $package = ServicePackage::create(['name' => 'Test', 'type' => 'package']);

        $response = $this->actingAs($this->getUser())
            ->getJson('/api/service-bookings/packages/' . $package->id);

        $response->assertStatus(200);
        $this->assertSame([], $response->json('models'));
    }

    public function testUpdatePackageSavesApplicableMakeAndModel()
    {
        $make = VehicleMake::factory()->create(['name' => 'Ford']);
        $model = VehicleModel::factory()->create(['name' => 'Focus', 'make_id' => $make->id]);
        $package = ServicePackage::create(['name' => 'Test', 'type' => 'package']);

        $response = $this->actingAs($this->getUser())
            ->putJson('/api/service-bookings/packages/' . $package->id, [
                'name' => 'Test',
                'type' => 'package',
                'description' => '',
                'applicable_make_id' => $make->id,
                'applicable_model_id' => $model->id,
            ]);

        $response->assertStatus(200);
        $package->refresh();
        $this->assertEquals($make->id, $package->applicable_make_id);
        $this->assertEquals($model->id, $package->applicable_model_id);
    }

    public function testUpdatePackageRejectsNonExistentModel()
    {
        $package = ServicePackage::create(['name' => 'Test', 'type' => 'package']);

        $response = $this->actingAs($this->getUser())
            ->putJson('/api/service-bookings/packages/' . $package->id, [
                'name' => 'Test',
                'type' => 'package',
                'description' => '',
                'applicable_model_id' => 999999,
            ]);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['applicable_model_id']);
    }

    public function testUpdatePackageAllowsClearingMakeAndModel()
    {
        $make = VehicleMake::factory()->create(['name' => 'Ford']);
        $model = VehicleModel::factory()->create(['name' => 'Focus', 'make_id' => $make->id]);
        $package = ServicePackage::create([
            'name' => 'Test',
            'type' => 'package',
            'applicable_make_id' => $make->id,
            'applicable_model_id' => $model->id,
        ]);

        $response = $this->actingAs($this->getUser())
            ->putJson('/api/service-bookings/packages/' . $package->id, [
                'name' => 'Test',
                'type' => 'package',
                'description' => '',
                'applicable_make_id' => null,
                'applicable_model_id' => null,
            ]);

        $response->assertStatus(200);
        $package->refresh();
        $this->assertNull($package->applicable_make_id);
        $this->assertNull($package->applicable_model_id);
    }

    public function testUpdatePackageWithValidData()
    {
        $package = ServicePackage::create([
            'name' => 'Original Name',
            'type' => 'package',
            'price' => 100,
            'description' => 'Original desc',
        ]);

        $response = $this->actingAs($this->getUser())
            ->putJson('/api/service-bookings/packages/' . $package->id, [
                'name' => 'Updated Name',
                'type' => 'add-on',
                'price' => 150,
                'description' => 'Updated desc',
            ]);

        $response->assertStatus(200);
        $package->refresh();
        $this->assertEquals('Updated Name', $package->name);
        $this->assertEquals('add-on', $package->type);
        $this->assertEquals(150, $package->price);
        $this->assertEquals('Updated desc', $package->description);
    }

    public function testUpdatePackageRequiresNameAndType()
    {
        $package = ServicePackage::create(['name' => 'Test', 'type' => 'package']);

        $response = $this->actingAs($this->getUser())
            ->putJson('/api/service-bookings/packages/' . $package->id, [
                'price' => 100,
                'description' => 'test',
            ]);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['name', 'type']);
    }

    public function testUpdatePackageValidatesTypeEnum()
    {
        $package = ServicePackage::create(['name' => 'Test', 'type' => 'package']);

        $response = $this->actingAs($this->getUser())
            ->putJson('/api/service-bookings/packages/' . $package->id, [
                'name' => 'Test',
                'type' => 'invalid-type',
                'description' => '',
            ]);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['type']);
    }

    public function testUpdatePackageValidatesPriceIsNumeric()
    {
        $package = ServicePackage::create(['name' => 'Test', 'type' => 'package']);

        $response = $this->actingAs($this->getUser())
            ->putJson('/api/service-bookings/packages/' . $package->id, [
                'name' => 'Test',
                'type' => 'package',
                'price' => 'not-a-number',
                'description' => '',
            ]);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['price']);
    }

    public function testDeletePackageRemovesRecord()
    {
        $package = ServicePackage::create(['name' => 'To Delete', 'type' => 'package']);
        $this->assertEquals(1, ServicePackage::count());

        $response = $this->actingAs($this->getUser())
            ->deleteJson('/api/service-bookings/packages/' . $package->id);

        $response->assertStatus(200);
        $this->assertEquals(0, ServicePackage::count());
    }

    public function testSaveOrderReordersPackages()
    {
        $packageA = ServicePackage::create(['name' => 'A', 'type' => 'package', 'order' => 0]);
        $packageB = ServicePackage::create(['name' => 'B', 'type' => 'package', 'order' => 1]);
        $packageC = ServicePackage::create(['name' => 'C', 'type' => 'package', 'order' => 2]);

        // Reorder: C first, A second, B third
        $response = $this->actingAs($this->getUser())
            ->putJson('/api/service-bookings/packages/order', [
                ['id' => $packageC->id],
                ['id' => $packageA->id],
                ['id' => $packageB->id],
            ]);

        $response->assertStatus(200);

        $packageA->refresh();
        $packageB->refresh();
        $packageC->refresh();

        $this->assertEquals(1, $packageA->order);
        $this->assertEquals(2, $packageB->order);
        $this->assertEquals(0, $packageC->order);
    }

    public function testListPackagesSortsByOrderByDefault()
    {
        ServicePackage::create(['name' => 'Third', 'type' => 'package', 'order' => 2]);
        ServicePackage::create(['name' => 'First', 'type' => 'package', 'order' => 0]);
        ServicePackage::create(['name' => 'Second', 'type' => 'package', 'order' => 1]);

        $response = $this->actingAs($this->getUser())
            ->getJson('/api/service-bookings/packages');

        $response->assertStatus(200);
        $names = collect($response->json('data'))->pluck('title')->toArray();
        $this->assertEquals(['First', 'Second', 'Third'], $names);
    }
}
