<?php

namespace Tenant;

use App\Facades\Feature;
use App\Http\Middleware\EnabledFeatureMiddleware;
use App\Http\Middleware\PreventRequestsIfTenantSuspended;
use App\Http\Middleware\SeoRedirectCheckMiddleware;
use App\Http\Middleware\TrackRequests;
use App\Repositories\DealBuilderRepository;
use Illuminate\Support\Facades\Session;
use Mtc\MercuryDataModels\DealBuilder\AddOn;
use Mtc\MercuryDataModels\DealBuilder\Deal;
use Mtc\MercuryDataModels\DealBuilder\DealPartExchange;
use Mtc\MercuryDataModels\DealBuilder\Status;
use Mtc\MercuryDataModels\Vehicle;
use Mtc\MercuryDataModels\VehicleValuation;
use Tests\TenantTestCase;

class DealBuilderControllerTest extends TenantTestCase
{
    protected function setUp(): void
    {
        parent::setUp();
        $this->withoutMiddleware([
            EnabledFeatureMiddleware::class,
            PreventRequestsIfTenantSuspended::class,
            SeoRedirectCheckMiddleware::class,
            TrackRequests::class,
        ]);
        Feature::shouldReceive('isEnabled')
            ->zeroOrMoreTimes()
            ->andReturn(true);
        Session::forget(DealBuilderRepository::DEAL_SESSION_KEY);
    }

    public function testCanStartNewDeal(): void
    {
        // Ensure clean state before test
        Session::forget(DealBuilderRepository::DEAL_SESSION_KEY);

        $vehicle = Vehicle::factory()->create(['price' => 25000, 'is_published' => true]);

        $response = $this
            ->postJson('/frontend/deal-builder/start', [
                'vehicle_id' => $vehicle->slug,
            ]);

        $response->assertSuccessful();
        $response->assertJsonStructure([
            'deal' => [
                'reference',
                'vehicle',
                'total_amount',
            ],
        ]);

        $this->assertDatabaseHas('deals', [
            'vehicle_id' => $vehicle->id,
            'status_id' => 0,
        ]);
    }

    public function testCannotStartDealForDifferentVehicleWithoutForce(): void
    {
        $vehicle1 = Vehicle::factory()->create(['is_published' => true]);
        $vehicle2 = Vehicle::factory()->create(['is_published' => true]);

        // Start deal for vehicle 1
        $deal = Deal::factory()->create(['vehicle_id' => $vehicle1->id]);
        Session::put(DealBuilderRepository::DEAL_SESSION_KEY, $deal->id);

        // Try to start deal for vehicle 2 without force
        $response = $this
            ->postJson('/frontend/deal-builder/start', ['vehicle_id' => $vehicle2->slug]);

        $response->assertStatus(422);
    }

    public function testCanForceNewDealForDifferentVehicle(): void
    {
        $vehicle1 = Vehicle::factory()->create(['is_published' => true]);
        $vehicle2 = Vehicle::factory()->create(['is_published' => true]);

        // Start deal for vehicle 1
        $deal = Deal::factory()->create(['vehicle_id' => $vehicle1->id]);
        Session::put(DealBuilderRepository::DEAL_SESSION_KEY, $deal->id);

        // Force new deal for vehicle 2
        $response = $this
            ->postJson('/frontend/deal-builder/start', [
                'vehicle_id' => $vehicle2->slug,
                'force_new' => true,
            ]);

        $response->assertSuccessful();
        $response->assertJsonPath('deal.vehicle.slug', $vehicle2->slug);
    }

    public function testSubmittedDealIsClearedWhenStartingNewDeal(): void
    {
        $vehicle = Vehicle::factory()->create(['is_published' => true]);
        $deal = Deal::factory()->submitted()->create(['vehicle_id' => $vehicle->id]);

        Session::put(DealBuilderRepository::DEAL_SESSION_KEY, $deal->id);

        $response = $this
            ->postJson('/frontend/deal-builder/start', ['vehicle_id' => $vehicle->slug]);

        $response->assertSuccessful();
        // Should create a new deal, not return the submitted one
        $this->assertNotEquals($deal->id, $response->json('deal.reference'));
    }

    public function testCanAddAddonToDeal(): void
    {
        $vehicle = Vehicle::factory()->create(['is_published' => true]);
        $deal = Deal::factory()->create(['vehicle_id' => $vehicle->id]);
        $addOn = AddOn::factory()->create(['price' => 500]);

        Session::put(DealBuilderRepository::DEAL_SESSION_KEY, $deal->id);

        $response = $this
            ->postJson('/frontend/deal-builder/add-add-on', [
                'add_on_id' => $addOn->id,
            ]);

        $response->assertSuccessful();
        $this->assertDatabaseHas('deal_add_ons', [
            'deal_id' => $deal->id,
            'add_on_id' => $addOn->id,
        ]);
    }

    public function testCanRemoveAddonFromDeal(): void
    {
        $vehicle = Vehicle::factory()->create(['is_published' => true]);
        $deal = Deal::factory()->create(['vehicle_id' => $vehicle->id]);
        $addOn = AddOn::factory()->create();

        $deal->addOns()->create([
            'add_on_id' => $addOn->id,
            'price' => $addOn->price,
            'payment_term' => 'total',
        ]);

        Session::put(DealBuilderRepository::DEAL_SESSION_KEY, $deal->id);

        $response = $this
            ->postJson('/frontend/deal-builder/remove-add-on', [
                'add_on_id' => $addOn->id,
            ]);

        $response->assertSuccessful();
        $this->assertDatabaseMissing('deal_add_ons', [
            'deal_id' => $deal->id,
            'add_on_id' => $addOn->id,
        ]);
    }

    public function testCanSetPaymentType(): void
    {
        $vehicle = Vehicle::factory()->create(['price' => 25000]);
        $deal = Deal::factory()->create([
            'vehicle_id' => $vehicle->id,
            'total_amount' => 25000,
        ]);

        Session::put(DealBuilderRepository::DEAL_SESSION_KEY, $deal->id);

        $response = $this
            ->postJson('/frontend/deal-builder/set-payment-type', [
                'payment_type' => 'enquiry',
            ]);

        $response->assertSuccessful();
        $response->assertJsonPath('deal.payment_type', 'enquiry');
    }

    public function testCanSubmitDealAsEnquiry(): void
    {
        $vehicle = Vehicle::factory()->create(['is_published' => true]);
        $deal = Deal::factory()->create([
            'vehicle_id' => $vehicle->id,
            'payment_type' => 'enquiry',
        ]);
        Status::factory()->initial()->create();

        Session::put(DealBuilderRepository::DEAL_SESSION_KEY, $deal->id);

        $response = $this
            ->postJson('/frontend/deal-builder/submit-deal', [
                'deal_reference' => $deal->reference,
                'first_name' => 'John',
                'last_name' => 'Doe',
                'email' => 'john@example.com',
                'contact_number' => '07123456789',
            ]);

        $response->assertSuccessful();

        $deal->refresh();
        $this->assertEquals('John', $deal->first_name);
        $this->assertEquals('Doe', $deal->last_name);
        $this->assertEquals('john@example.com', $deal->email);
    }

    public function testCannotSubmitAlreadySubmittedDeal(): void
    {
        $vehicle = Vehicle::factory()->create(['is_published' => true]);
        $deal = Deal::factory()->submitted()->create(['vehicle_id' => $vehicle->id]);

        Session::put(DealBuilderRepository::DEAL_SESSION_KEY, $deal->id);

        $response = $this
            ->postJson('/frontend/deal-builder/submit-deal', [
                'deal_reference' => $deal->reference,
                'first_name' => 'John',
                'last_name' => 'Doe',
                'email' => 'john@example.com',
                'contact_number' => '07123456789',
            ]);

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

    public function testSubmitDealRequiresContactDetails(): void
    {
        $vehicle = Vehicle::factory()->create(['is_published' => true]);
        $deal = Deal::factory()->create(['vehicle_id' => $vehicle->id]);

        Session::put(DealBuilderRepository::DEAL_SESSION_KEY, $deal->id);

        $response = $this
            ->postJson('/frontend/deal-builder/submit-deal', [
                'deal_reference' => $deal->reference,
            ]);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['first_name', 'last_name', 'email', 'contact_number']);
    }

    public function testPartExchangeLimitsToOneWhenSettingDisabled(): void
    {
        $vehicle = Vehicle::factory()->create(['is_published' => true]);
        $deal = Deal::factory()->create(['vehicle_id' => $vehicle->id]);
        $valuation = VehicleValuation::factory()->create();

        // Add first part exchange
        DealPartExchange::factory()->create(['deal_id' => $deal->id]);

        Session::put(DealBuilderRepository::DEAL_SESSION_KEY, $deal->id);

        $response = $this
            ->postJson('/frontend/deal-builder/add-part-exchange', [
                'valuation_id' => $valuation->id,
                'registration' => 'AB12 CDE',
                'mileage' => 50000,
                'email' => 'test@example.com',
                'outstanding_finance' => 0,
                'cashback_amount' => 0,
            ]);

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

    public function testAllowedPaymentTypesRestrictedWhenTotalIsZero(): void
    {
        $vehicle = Vehicle::factory()->create(['price' => 10000]);
        $deal = Deal::factory()->create([
            'vehicle_id' => $vehicle->id,
            'total_amount' => 0,
        ]);

        Session::put(DealBuilderRepository::DEAL_SESSION_KEY, $deal->id);

        $response = $this
            ->getJson('/frontend/deal-builder');

        $response->assertSuccessful();
        $response->assertJsonPath('allowed_payment_types.enquiry', true);
        $response->assertJsonPath('allowed_payment_types.deposit', false);
        $response->assertJsonPath('allowed_payment_types.full_payment', false);
    }

    public function testCanUpdatePartExchange(): void
    {
        $vehicle = Vehicle::factory()->create(['is_published' => true]);
        $deal = Deal::factory()->create(['vehicle_id' => $vehicle->id]);
        $partExchange = DealPartExchange::factory()->create([
            'deal_id' => $deal->id,
            'retail_price' => 10000,
            'outstanding_finance' => 0,
            'cashback_amount' => 0,
        ]);

        Session::put(DealBuilderRepository::DEAL_SESSION_KEY, $deal->id);

        $response = $this
            ->postJson('/frontend/deal-builder/update-part-exchange', [
                'id' => $partExchange->id,
                'outstanding_finance' => 2000,
                'cashback_amount' => 500,
            ]);

        $response->assertSuccessful();

        $partExchange->refresh();
        $this->assertEquals(2000, $partExchange->outstanding_finance);
        $this->assertEquals(500, $partExchange->cashback_amount);
    }

    public function testCashbackCannotExceedValuationMinusFinance(): void
    {
        $vehicle = Vehicle::factory()->create(['is_published' => true]);
        $deal = Deal::factory()->create(['vehicle_id' => $vehicle->id]);
        $partExchange = DealPartExchange::factory()->create([
            'deal_id' => $deal->id,
            'retail_price' => 10000,
            'outstanding_finance' => 3000,
            'cashback_amount' => 0,
        ]);

        Session::put(DealBuilderRepository::DEAL_SESSION_KEY, $deal->id);

        // Try to set cashback higher than valuation - finance (10000 - 3000 = 7000)
        $response = $this
            ->postJson('/frontend/deal-builder/update-part-exchange', [
                'id' => $partExchange->id,
                'outstanding_finance' => 3000,
                'cashback_amount' => 8000, // Exceeds max of 7000
            ]);

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

    public function testCanRemovePartExchange(): void
    {
        $vehicle = Vehicle::factory()->create(['is_published' => true]);
        $deal = Deal::factory()->create(['vehicle_id' => $vehicle->id]);
        $partExchange = DealPartExchange::factory()->create(['deal_id' => $deal->id]);

        Session::put(DealBuilderRepository::DEAL_SESSION_KEY, $deal->id);

        $response = $this
            ->postJson('/frontend/deal-builder/remove-part-exchange', [
                'part_exchange_id' => $partExchange->id,
            ]);

        $response->assertSuccessful();
        $this->assertDatabaseMissing('deal_part_exchanges', ['id' => $partExchange->id]);
    }
}
