<?php

namespace Tests\Tenant;

use Carbon\Carbon;
use Mtc\MercuryDataModels\DealBuilder\DeliveryConfig;
use Mtc\MercuryDataModels\DealBuilder\DeliveryHoliday;
use Mtc\MercuryDataModels\DealBuilder\DeliveryLocation;
use Mtc\MercuryDataModels\DealBuilder\DeliveryPriceTier;
use Mtc\MercuryDataModels\Dealership;
use Tests\TenantTestCase;
use Tests\UserForTenant;

class DealBuilderDeliveryControllerTest extends TenantTestCase
{
    use UserForTenant;

    public function testListDeliveryConfigReturnsDealerships()
    {
        Dealership::factory()->create(['name' => 'Dealer A']);
        Dealership::factory()->create(['name' => 'Dealer B']);

        $response = $this->actingAs($this->getUser())
            ->getJson('/api/deal-delivery-config');

        $response->assertStatus(200);
        $this->assertCount(2, $response->json());
    }

    public function testListDeliveryConfigShowsActiveStatus()
    {
        $activeDealership = Dealership::factory()->create(['name' => 'Active Dealer']);
        DeliveryConfig::create([
            'dealership_id' => $activeDealership->id,
            'active' => true,
            'max_concurrent_deliveries' => 2,
        ]);

        $inactiveDealership = Dealership::factory()->create(['name' => 'Inactive Dealer']);

        $response = $this->actingAs($this->getUser())
            ->getJson('/api/deal-delivery-config');

        $response->assertStatus(200);
        $dealers = collect($response->json());

        $active = $dealers->firstWhere('id', $activeDealership->id);
        $this->assertEquals('Delivery active', $active['metaItems']['active']);
        $this->assertTrue($active['has_config']);

        $inactive = $dealers->firstWhere('id', $inactiveDealership->id);
        $this->assertEquals('', $inactive['metaItems']['active']);
        $this->assertFalse($inactive['has_config']);
    }

    public function testShowDeliveryConfigReturnsDealershipWithConfig()
    {
        $dealership = Dealership::factory()->create(['name' => 'Test Dealer']);
        $config = DeliveryConfig::create([
            'dealership_id' => $dealership->id,
            'active' => true,
            'allow_home_delivery' => true,
            'max_delivery_distance' => 25.00,
            'max_concurrent_deliveries' => 3,
            'time_windows' => ['10:00', '14:00'],
            'mondays' => true,
            'tuesdays' => true,
            'wednesdays' => true,
            'thursdays' => true,
            'fridays' => true,
            'saturdays' => false,
            'sundays' => false,
            'min_days_in_future' => 1,
            'max_days_in_future' => 60,
        ]);

        DeliveryLocation::create([
            'delivery_config_id' => $config->id,
            'name' => 'City Centre Hub',
            'postcode' => 'M1 1AA',
            'fee' => 50.00,
        ]);

        DeliveryPriceTier::create([
            'delivery_config_id' => $config->id,
            'from_miles' => 0,
            'to_miles' => 10,
            'fee' => 25.00,
        ]);

        $response = $this->actingAs($this->getUser())
            ->getJson('/api/deal-delivery-config/' . $dealership->id);

        $response->assertStatus(200);

        $this->assertEquals($dealership->id, $response->json('location.id'));
        $this->assertEquals('Test Dealer', $response->json('location.name'));

        $configData = $response->json('config');
        $this->assertTrue($configData['active']);
        $this->assertTrue($configData['allow_home_delivery']);
        $this->assertEquals('25.00', $configData['max_delivery_distance']);
        $this->assertEquals(3, $configData['max_concurrent_deliveries']);
        $this->assertCount(1, $configData['locations']);
        $this->assertEquals('City Centre Hub', $configData['locations'][0]['name']);
        $this->assertCount(1, $configData['price_tiers']);
        $this->assertEquals('25.00', $configData['price_tiers'][0]['fee']);
    }

    public function testShowDeliveryConfigIncludesUpcomingHolidays()
    {
        $dealership = Dealership::factory()->create();
        $config = DeliveryConfig::create([
            'dealership_id' => $dealership->id,
            'active' => true,
            'max_concurrent_deliveries' => 1,
        ]);

        DeliveryHoliday::create([
            'delivery_config_id' => $config->id,
            'holiday_date' => Carbon::now()->addMonth()->format('Y-m-d'),
        ]);
        DeliveryHoliday::create([
            'delivery_config_id' => $config->id,
            'holiday_date' => Carbon::now()->subMonth()->format('Y-m-d'),
        ]);

        $response = $this->actingAs($this->getUser())
            ->getJson('/api/deal-delivery-config/' . $dealership->id);

        $response->assertStatus(200);
        $holidays = $response->json('config.holidays');
        $this->assertCount(1, $holidays);
    }

    public function testUpdateCreatesNewDeliveryConfig()
    {
        $dealership = Dealership::factory()->create();
        $this->assertEquals(0, DeliveryConfig::count());

        $response = $this->actingAs($this->getUser())
            ->putJson('/api/deal-delivery-config/' . $dealership->id, [
                'active' => true,
                'allow_home_delivery' => true,
                'max_delivery_distance' => 30,
                'max_concurrent_deliveries' => 2,
                'time_windows' => ['10:00', '14:00'],
                'mondays' => true,
                'tuesdays' => true,
                'wednesdays' => true,
                'thursdays' => true,
                'fridays' => true,
                'saturdays' => false,
                'sundays' => false,
                'min_days_in_future' => 1,
                'max_days_in_future' => 60,
                'holidays' => [],
                'locations' => [],
                'price_tiers' => [],
            ]);

        $response->assertStatus(200);
        $this->assertEquals(1, DeliveryConfig::count());

        $config = DeliveryConfig::first();
        $this->assertEquals($dealership->id, $config->dealership_id);
        $this->assertTrue($config->active);
        $this->assertTrue($config->allow_home_delivery);
        $this->assertEquals(30, $config->max_delivery_distance);
        $this->assertEquals(2, $config->max_concurrent_deliveries);
    }

    public function testUpdateSyncsLocations()
    {
        $dealership = Dealership::factory()->create();
        $config = DeliveryConfig::create([
            'dealership_id' => $dealership->id,
            'active' => true,
            'max_concurrent_deliveries' => 1,
        ]);

        $existingLocation = DeliveryLocation::create([
            'delivery_config_id' => $config->id,
            'name' => 'Old Location',
            'fee' => 10.00,
        ]);

        $response = $this->actingAs($this->getUser())
            ->putJson('/api/deal-delivery-config/' . $dealership->id, [
                'active' => true,
                'max_concurrent_deliveries' => 1,
                'holidays' => [],
                'locations' => [
                    [
                        'id' => $existingLocation->id,
                        'name' => 'Updated Location',
                        'fee' => 15.00,
                    ],
                    [
                        'name' => 'New Location',
                        'postcode' => 'SW1A 1AA',
                        'fee' => 25.00,
                    ],
                ],
                'price_tiers' => [],
            ]);

        $response->assertStatus(200);
        $this->assertEquals(2, DeliveryLocation::count());

        $updated = DeliveryLocation::find($existingLocation->id);
        $this->assertEquals('Updated Location', $updated->name);
        $this->assertEquals('15.00', $updated->fee);
    }

    public function testUpdateReplacesPriceTiers()
    {
        $dealership = Dealership::factory()->create();
        $config = DeliveryConfig::create([
            'dealership_id' => $dealership->id,
            'active' => true,
            'max_concurrent_deliveries' => 1,
        ]);

        DeliveryPriceTier::create([
            'delivery_config_id' => $config->id,
            'from_miles' => 0,
            'to_miles' => 5,
            'fee' => 10.00,
        ]);

        $response = $this->actingAs($this->getUser())
            ->putJson('/api/deal-delivery-config/' . $dealership->id, [
                'active' => true,
                'max_concurrent_deliveries' => 1,
                'holidays' => [],
                'locations' => [],
                'price_tiers' => [
                    ['from_miles' => 0, 'to_miles' => 10, 'fee' => 20.00],
                    ['from_miles' => 10, 'to_miles' => 25, 'fee' => 40.00],
                ],
            ]);

        $response->assertStatus(200);
        $this->assertEquals(2, DeliveryPriceTier::count());

        $tiers = DeliveryPriceTier::orderBy('from_miles')->get();
        $this->assertEquals('20.00', $tiers[0]->fee);
        $this->assertEquals('40.00', $tiers[1]->fee);
    }

    public function testUpdateDeliveryConfigAllocatesHolidays()
    {
        $dealership = Dealership::factory()->create();

        $futureDate1 = Carbon::now()->addWeeks(2)->format('Y-m-d');
        $futureDate2 = Carbon::now()->addWeeks(4)->format('Y-m-d');

        $response = $this->actingAs($this->getUser())
            ->putJson('/api/deal-delivery-config/' . $dealership->id, [
                'active' => true,
                'max_concurrent_deliveries' => 1,
                'holidays' => [$futureDate1, $futureDate2],
                'locations' => [],
                'price_tiers' => [],
            ]);

        $response->assertStatus(200);
        $this->assertEquals(2, DeliveryHoliday::count());

        $holidayDates = DeliveryHoliday::pluck('holiday_date')
            ->map(fn ($d) => Carbon::parse($d)->format('Y-m-d'))
            ->toArray();
        $this->assertContains($futureDate1, $holidayDates);
        $this->assertContains($futureDate2, $holidayDates);
    }

    public function testUpdateDeliveryConfigValidatesRequiredFields()
    {
        $dealership = Dealership::factory()->create();

        $response = $this->actingAs($this->getUser())
            ->putJson('/api/deal-delivery-config/' . $dealership->id, []);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['active', 'max_concurrent_deliveries']);
    }

    public function testUpdateDeliveryConfigValidatesLocationFields()
    {
        $dealership = Dealership::factory()->create();

        $response = $this->actingAs($this->getUser())
            ->putJson('/api/deal-delivery-config/' . $dealership->id, [
                'active' => true,
                'max_concurrent_deliveries' => 1,
                'locations' => [
                    ['fee' => 10.00],
                ],
                'price_tiers' => [],
            ]);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['locations.0.name']);
    }

    public function testUpdateDeliveryConfigValidatesPriceTierFields()
    {
        $dealership = Dealership::factory()->create();

        $response = $this->actingAs($this->getUser())
            ->putJson('/api/deal-delivery-config/' . $dealership->id, [
                'active' => true,
                'max_concurrent_deliveries' => 1,
                'locations' => [],
                'price_tiers' => [
                    ['from_miles' => 0],
                ],
            ]);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['price_tiers.0.to_miles', 'price_tiers.0.fee']);
    }
}
