<?php

namespace Tests\Feature;

use App\Models\Central\Company;
use App\Models\Central\Plan;
use App\Models\Tenant\Client;
use App\Models\Tenant\MarkupRule;
use App\Models\Tenant\Part;
use App\Models\Tenant\PricingCoefficient;
use App\Models\Tenant\Vehicle;
use App\Services\Pricing\PricingEngine;
use App\Tenancy\TenantManager;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class PricingEngineTest extends TestCase
{
    use RefreshDatabase;

    private PricingEngine $engine;

    protected function setUp(): void
    {
        parent::setUp();
        $this->engine = app(PricingEngine::class);
        $this->makeCompany('pricing');
    }

    public function test_base_markup_only_when_no_coefficients(): void
    {
        MarkupRule::create(['type' => 'category', 'key' => 'Frâne', 'markup_pct' => 50, 'priority' => 10, 'is_active' => true]);
        $part = Part::create(['name' => 'Disc', 'category' => 'Frâne', 'buy_price' => 100, 'sell_price' => 0, 'qty' => 1, 'unit' => 'buc', 'is_active' => true]);

        $q = $this->engine->quote($part);
        $this->assertEquals(150.0, $q['base']);
        $this->assertEquals(150.0, $q['final']);
        $this->assertEmpty($q['applied']);
    }

    public function test_old_vehicle_age_coefficient_applies(): void
    {
        $part = Part::create(['name' => 'Filtru', 'buy_price' => 100, 'sell_price' => 130, 'qty' => 1, 'unit' => 'buc', 'is_active' => true]);
        PricingCoefficient::create([
            'name' => 'Mașină veche', 'multiplier' => 1.20, 'priority' => 10,
            'stackable' => true, 'is_active' => true,
            'conditions' => ['age_min' => 10],
        ]);

        $oldCar = $this->makeVehicle(year: (int) date('Y') - 15);
        $q = $this->engine->quote($part, $oldCar);
        $this->assertEqualsWithDelta(156.0, $q['final'], 0.01); // 130 × 1.20

        $newCar = $this->makeVehicle(year: (int) date('Y') - 2);
        $q2 = $this->engine->quote($part, $newCar);
        $this->assertEqualsWithDelta(130.0, $q2['final'], 0.01); // no coefficient
    }

    public function test_vip_client_coefficient(): void
    {
        $part = Part::create(['name' => 'P', 'buy_price' => 100, 'sell_price' => 100, 'qty' => 1, 'unit' => 'buc', 'is_active' => true]);
        PricingCoefficient::create([
            'name' => 'Discount VIP', 'multiplier' => 0.90, 'priority' => 10,
            'stackable' => true, 'is_active' => true,
            'conditions' => ['client_vip' => true],
        ]);

        $vip = Client::create(['name' => 'VIP', 'phone' => '+37360000001', 'type' => 'individual', 'status' => 'active', 'is_vip' => true]);
        $regular = Client::create(['name' => 'Reg', 'phone' => '+37360000002', 'type' => 'individual', 'status' => 'active', 'is_vip' => false]);

        $this->assertEqualsWithDelta(90.0, $this->engine->quote($part, null, $vip)['final'], 0.01);
        $this->assertEqualsWithDelta(100.0, $this->engine->quote($part, null, $regular)['final'], 0.01);
    }

    public function test_express_urgency_coefficient(): void
    {
        $part = Part::create(['name' => 'P', 'buy_price' => 100, 'sell_price' => 100, 'qty' => 1, 'unit' => 'buc', 'is_active' => true]);
        PricingCoefficient::create([
            'name' => 'Express', 'multiplier' => 1.30, 'priority' => 10,
            'stackable' => true, 'is_active' => true,
            'conditions' => ['urgency' => ['express']],
        ]);

        $this->assertEqualsWithDelta(130.0, $this->engine->quote($part, null, null, 'express')['final'], 0.01);
        $this->assertEqualsWithDelta(100.0, $this->engine->quote($part, null, null, 'normal')['final'], 0.01);
    }

    public function test_stackable_multiply_nonstackable_take_highest(): void
    {
        $part = Part::create(['name' => 'P', 'buy_price' => 100, 'sell_price' => 100, 'qty' => 1, 'unit' => 'buc', 'is_active' => true]);

        // Two stackable + two non-stackable, all matching (no conditions).
        PricingCoefficient::create(['name' => 'S1', 'multiplier' => 1.10, 'stackable' => true, 'is_active' => true, 'priority' => 1]);
        PricingCoefficient::create(['name' => 'S2', 'multiplier' => 1.20, 'stackable' => true, 'is_active' => true, 'priority' => 2]);
        PricingCoefficient::create(['name' => 'N1', 'multiplier' => 1.50, 'stackable' => false, 'is_active' => true, 'priority' => 3]);
        PricingCoefficient::create(['name' => 'N2', 'multiplier' => 1.30, 'stackable' => false, 'is_active' => true, 'priority' => 4]);

        // 100 × 1.10 × 1.20 × max(1.50,1.30) = 100 × 1.32 × 1.50 = 198
        $q = $this->engine->quote($part);
        $this->assertEqualsWithDelta(198.0, $q['final'], 0.01);
        $this->assertCount(3, $q['applied']); // S1, S2, N1 (only strongest non-stackable)
    }

    public function test_hybrid_inferred_from_fuel(): void
    {
        $part = Part::create(['name' => 'P', 'buy_price' => 100, 'sell_price' => 100, 'qty' => 1, 'unit' => 'buc', 'is_active' => true]);
        PricingCoefficient::create([
            'name' => 'Hibrid', 'multiplier' => 1.25, 'stackable' => true, 'is_active' => true, 'priority' => 1,
            'conditions' => ['classes' => ['hybrid']],
        ]);

        // No explicit vehicle_class, but fuel = Hybrid.
        $car = $this->makeVehicle(year: 2020, fuel: 'Hybrid');
        $this->assertEqualsWithDelta(125.0, $this->engine->quote($part, $car)['final'], 0.01);
    }

    private function makeCompany(string $slug): Company
    {
        $plan = Plan::firstOrCreate(['slug' => 'test'], ['name' => 'T', 'price' => 0, 'features' => []]);
        $company = Company::create(['plan_id' => $plan->id, 'slug' => $slug, 'name' => 'P', 'status' => 'active']);
        app(TenantManager::class)->setCurrent($company);
        return $company;
    }

    private function makeVehicle(int $year, ?string $fuel = null): Vehicle
    {
        $client = Client::create(['name' => 'C', 'phone' => '+3736' . random_int(1000000, 9999999), 'type' => 'individual', 'status' => 'active']);
        return Vehicle::create([
            'client_id' => $client->id,
            'make' => 'X', 'model' => 'Y', 'year' => $year,
            'fuel' => $fuel, 'plate' => 'P' . random_int(100, 999),
        ]);
    }
}
