<?php

namespace Tests\Feature;

use App\Models\Central\Company;
use App\Models\Central\Plan;
use App\Models\Tenant\Client;
use App\Models\Tenant\Labor;
use App\Models\Tenant\LaborPart;
use App\Models\Tenant\Part;
use App\Models\Tenant\ServiceTemplate;
use App\Models\Tenant\ServiceTemplateItem;
use App\Models\Tenant\Vehicle;
use App\Models\Tenant\WorkOrder;
use App\Services\ServiceComposer;
use App\Tenancy\TenantManager;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class ServiceComposerTest extends TestCase
{
    use RefreshDatabase;

    private ServiceComposer $composer;
    private Company $company;

    protected function setUp(): void
    {
        parent::setUp();
        $this->composer = app(ServiceComposer::class);
        $this->company = $this->makeCompany('compose', laborRate: 500);
    }

    public function test_add_hourly_labor_uses_rate_times_hours(): void
    {
        $labor = Labor::create(['category' => 'Motor', 'name_ro' => 'Schimb ulei', 'hours' => 1.5, 'pricing_mode' => 'hourly', 'is_active' => true]);
        $wo = $this->makeWorkOrder();

        $work = $this->composer->addLabor($wo, $labor);

        $this->assertEquals(1.5, (float) $work->hours);
        $this->assertEquals(500.0, (float) $work->price_per_hour);
        $this->assertEquals(750.0, (float) $work->total); // 1.5 × 500
    }

    public function test_add_fixed_labor_uses_fixed_price(): void
    {
        $labor = Labor::create(['category' => 'ITP', 'name_ro' => 'Diagnostic', 'hours' => 1, 'pricing_mode' => 'fixed', 'fixed_price' => 300, 'is_active' => true]);
        $wo = $this->makeWorkOrder();

        $work = $this->composer->addLabor($wo, $labor);

        $this->assertEquals(300.0, (float) $work->total);
    }

    public function test_labor_auto_adds_default_parts(): void
    {
        $labor = Labor::create(['category' => 'Motor', 'name_ro' => 'Schimb ulei', 'hours' => 1, 'pricing_mode' => 'hourly', 'is_active' => true]);
        $oil = Part::create(['name' => 'Ulei 5W30', 'sell_price' => 60, 'buy_price' => 40, 'qty' => 100, 'unit' => 'L', 'is_active' => true]);
        $filter = Part::create(['name' => 'Filtru ulei', 'sell_price' => 80, 'buy_price' => 50, 'qty' => 20, 'unit' => 'buc', 'is_active' => true]);
        LaborPart::create(['labor_id' => $labor->id, 'part_id' => $oil->id, 'qty' => 4, 'unit' => 'L']);
        LaborPart::create(['labor_id' => $labor->id, 'part_id' => $filter->id, 'qty' => 1, 'unit' => 'buc']);

        $wo = $this->makeWorkOrder();
        $this->composer->addLabor($wo, $labor, withParts: true);

        $this->assertEquals(2, $wo->parts()->count());
        $oilLine = $wo->parts()->where('part_id', $oil->id)->first();
        $this->assertEquals(4.0, (float) $oilLine->qty);
        $this->assertEquals(60.0, (float) $oilLine->sell_price);
    }

    public function test_add_labor_without_parts_skips_defaults(): void
    {
        $labor = Labor::create(['category' => 'Motor', 'name_ro' => 'X', 'hours' => 1, 'pricing_mode' => 'hourly', 'is_active' => true]);
        $p = Part::create(['name' => 'P', 'sell_price' => 10, 'buy_price' => 5, 'qty' => 5, 'unit' => 'buc', 'is_active' => true]);
        LaborPart::create(['labor_id' => $labor->id, 'part_id' => $p->id, 'qty' => 1]);

        $wo = $this->makeWorkOrder();
        $this->composer->addLabor($wo, $labor, withParts: false);

        $this->assertEquals(0, $wo->parts()->count());
    }

    public function test_apply_template_adds_all_lines_and_recalcs(): void
    {
        $labor = Labor::create(['category' => 'Motor', 'name_ro' => 'Schimb ulei', 'hours' => 1, 'pricing_mode' => 'hourly', 'is_active' => true]);
        $oil = Part::create(['name' => 'Ulei', 'sell_price' => 60, 'buy_price' => 40, 'qty' => 100, 'unit' => 'L', 'is_active' => true]);

        $tpl = ServiceTemplate::create(['name' => 'Revizie', 'is_active' => true]);
        ServiceTemplateItem::create(['service_template_id' => $tpl->id, 'kind' => 'labor', 'labor_id' => $labor->id, 'name' => 'Schimb ulei', 'hours' => 1]);
        ServiceTemplateItem::create(['service_template_id' => $tpl->id, 'kind' => 'part', 'part_id' => $oil->id, 'name' => 'Ulei', 'qty' => 4]);

        $wo = $this->makeWorkOrder();
        $r = $this->composer->applyTemplate($wo, $tpl->load('items'));

        $this->assertEquals(1, $r['labor']);
        $this->assertEquals(1, $r['parts']);
        $this->assertEquals(1, $wo->works()->count());
        $this->assertEquals(1, $wo->parts()->count());

        $wo->refresh();
        // labor 1×500 + oil 4×60 = 500 + 240 = 740
        $this->assertEquals(740.0, (float) $wo->total);
    }

    public function test_templates_isolated_per_tenant(): void
    {
        ServiceTemplate::create(['name' => 'A', 'is_active' => true]);
        $other = $this->makeCompany('other', laborRate: 400);
        app(TenantManager::class)->setCurrent($other);
        $this->assertEquals(0, ServiceTemplate::count());
    }

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

    private function makeWorkOrder(): WorkOrder
    {
        $client = Client::create(['name' => 'C', 'phone' => '+3736' . random_int(1000000, 9999999), 'type' => 'individual', 'status' => 'active']);
        $vehicle = Vehicle::create(['client_id' => $client->id, 'make' => 'X', 'model' => 'Y', 'plate' => 'P' . random_int(100, 999)]);
        return WorkOrder::create([
            'number' => WorkOrder::generateNumber($this->company->id),
            'client_id' => $client->id, 'vehicle_id' => $vehicle->id,
            'opened_at' => now(), 'status' => 'in_work',
        ]);
    }
}
