<?php

namespace Tests\Feature;

use App\Models\Central\Company;
use App\Models\Central\Plan;
use App\Models\Tenant\Client;
use App\Models\Tenant\ClientNotificationLog;
use App\Models\Tenant\Part;
use App\Models\Tenant\PricingApplicationLog;
use App\Models\Tenant\PricingCoefficient;
use App\Models\Tenant\User;
use App\Models\Tenant\Vehicle;
use App\Models\Tenant\WorkOrder;
use App\Models\Tenant\WorkOrderWork;
use App\Services\Pricing\PricingEngine;
use App\Tenancy\TenantManager;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Laravel\Sanctum\Sanctum;
use Tests\TestCase;

class PolishTier3Test extends TestCase
{
    use RefreshDatabase;

    private Company $company;

    protected function setUp(): void
    {
        parent::setUp();
        $plan = Plan::firstOrCreate(['slug' => 'test'], ['name' => 'T', 'price' => 0, 'features' => []]);
        $this->company = Company::create(['plan_id' => $plan->id, 'slug' => 't3-' . uniqid(), 'name' => 'T3', 'status' => 'active']);
        app(TenantManager::class)->setCurrent($this->company);
    }

    private function makeClient(string $prefix = ''): Client
    {
        return Client::create(['name' => $prefix . 'C', 'phone' => '+3739900' . random_int(1000, 9999), 'type' => 'individual', 'status' => 'active']);
    }

    // ── M12 ──
    public function test_pricing_engine_matches_body_type_condition(): void
    {
        PricingCoefficient::create([
            'name' => 'Pickup +20%', 'multiplier' => 1.20,
            'conditions' => ['body_types' => ['pickup']],
            'stackable' => true, 'priority' => 100, 'is_active' => true,
        ]);
        $part = Part::create(['name' => 'P', 'article' => 'X', 'buy_price' => 100, 'sell_price' => 100]);
        $pickup = Vehicle::create(['client_id' => $this->makeClient('p')->id, 'make' => 'Ford', 'model' => 'Ranger', 'plate' => 'P1', 'body_type' => 'pickup']);
        $sedan = Vehicle::create(['client_id' => $this->makeClient('s')->id, 'make' => 'BMW', 'model' => 'X5', 'plate' => 'S1', 'body_type' => 'sedan']);

        $q1 = app(PricingEngine::class)->quote($part, $pickup);
        $q2 = app(PricingEngine::class)->quote($part, $sedan);

        $this->assertCount(1, $q1['applied']);
        $this->assertEmpty($q2['applied']);
    }

    public function test_pricing_engine_matches_transmission_dsg(): void
    {
        PricingCoefficient::create([
            'name' => 'DSG +15%', 'multiplier' => 1.15,
            'conditions' => ['transmissions' => ['dsg']],
            'stackable' => true, 'priority' => 100, 'is_active' => true,
        ]);
        $part = Part::create(['name' => 'P', 'article' => 'X', 'buy_price' => 100, 'sell_price' => 100]);
        $dsg = Vehicle::create(['client_id' => $this->makeClient('d')->id, 'make' => 'VW', 'model' => 'Golf', 'plate' => 'D1', 'transmission_type' => 'dsg']);

        $q = app(PricingEngine::class)->quote($part, $dsg);
        $this->assertCount(1, $q['applied']);
        $this->assertEquals('DSG +15%', $q['applied'][0]['name']);
    }

    public function test_pricing_log_persists_breakdown(): void
    {
        PricingCoefficient::create([
            'name' => 'SUV +15%', 'multiplier' => 1.15,
            'conditions' => ['classes' => ['suv']],
            'stackable' => true, 'priority' => 100, 'is_active' => true,
        ]);
        $part = Part::create(['name' => 'P', 'article' => 'X', 'buy_price' => 100, 'sell_price' => 150]);
        $client = $this->makeClient('pl');
        $vehicle = Vehicle::create(['client_id' => $client->id, 'make' => 'BMW', 'model' => 'X5', 'plate' => 'X1', 'vehicle_class' => 'suv', 'year' => 2020]);
        $wo = WorkOrder::create(['number' => WorkOrder::generateNumber($this->company->id), 'client_id' => $client->id, 'vehicle_id' => $vehicle->id, 'opened_at' => today(), 'status' => 'in_work', 'total' => 0]);
        $line = \App\Models\Tenant\WorkOrderPart::create(['work_order_id' => $wo->id, 'name' => 'P', 'qty' => 1, 'sell_price' => 150]);

        $quote = app(PricingEngine::class)->quote($part, $vehicle, $client);
        $log = app(PricingEngine::class)->logApplication($quote, $line, $vehicle, $client, $part);

        $this->assertEqualsWithDelta(150.0, (float) $log->base_price, 0.01);
        $this->assertEqualsWithDelta(172.5, (float) $log->final_price, 0.01);
        $this->assertCount(1, $log->applied_coefficients);
        $this->assertEquals('suv', $log->context['class']);
    }

    // ── M13 ──
    public function test_mechanic_api_board_returns_only_own_wos(): void
    {
        $mech = User::create(['name' => 'M', 'email' => 'm@e.com', 'password' => bcrypt('x'), 'role' => 'mechanic', 'status' => 'active']);
        $other = User::create(['name' => 'O', 'email' => 'o@e.com', 'password' => bcrypt('x'), 'role' => 'mechanic', 'status' => 'active']);
        WorkOrder::create(['number' => WorkOrder::generateNumber($this->company->id), 'master_id' => $mech->id, 'opened_at' => today(), 'status' => 'in_work', 'total' => 100]);
        WorkOrder::create(['number' => WorkOrder::generateNumber($this->company->id), 'master_id' => $other->id, 'opened_at' => today(), 'status' => 'in_work', 'total' => 200]);

        Sanctum::actingAs($mech);
        $resp = $this->getJson('/api/v1/mechanic/board');
        $resp->assertOk();
        $this->assertCount(1, $resp->json('data'));
    }

    public function test_mechanic_api_start_task_only_own(): void
    {
        $mech = User::create(['name' => 'M', 'email' => 'm@e.com', 'password' => bcrypt('x'), 'role' => 'mechanic', 'status' => 'active']);
        $other = User::create(['name' => 'O', 'email' => 'o@e.com', 'password' => bcrypt('x'), 'role' => 'mechanic', 'status' => 'active']);
        $foreignWo = WorkOrder::create(['number' => WorkOrder::generateNumber($this->company->id), 'master_id' => $other->id, 'opened_at' => today(), 'status' => 'in_work', 'total' => 0]);
        $foreignWork = WorkOrderWork::create(['work_order_id' => $foreignWo->id, 'name' => "Other's", 'hours' => 1, 'price_per_hour' => 100]);

        Sanctum::actingAs($mech);
        $resp = $this->postJson("/api/v1/mechanic/tasks/{$foreignWork->id}/start");
        $resp->assertForbidden();
    }

    public function test_mechanic_kpi_endpoint_aggregates_period(): void
    {
        $mech = User::create(['name' => 'M', 'email' => 'm@e.com', 'password' => bcrypt('x'), 'role' => 'mechanic', 'status' => 'active']);
        $wo = WorkOrder::create(['number' => WorkOrder::generateNumber($this->company->id), 'master_id' => $mech->id, 'opened_at' => today(), 'status' => 'in_work', 'total' => 0]);

        // Two done works in 2026-06
        WorkOrderWork::create(['work_order_id' => $wo->id, 'name' => 'A', 'hours' => 2, 'price_per_hour' => 300, 'mechanic_status' => 'done', 'actual_hours' => 1.5, 'mechanic_done_at' => '2026-06-10 10:00:00']);
        WorkOrderWork::create(['work_order_id' => $wo->id, 'name' => 'B', 'hours' => 1, 'price_per_hour' => 300, 'mechanic_status' => 'done', 'actual_hours' => 1.0, 'mechanic_done_at' => '2026-06-15 10:00:00']);

        Sanctum::actingAs($mech);
        $resp = $this->getJson('/api/v1/mechanic/kpi?period=2026-06');
        $resp->assertOk();
        $this->assertEquals(2, $resp->json('tasks_done'));
        $this->assertEqualsWithDelta(3.0, $resp->json('norm_hours'), 0.01);
        $this->assertEqualsWithDelta(2.5, $resp->json('actual_hours'), 0.01);
        $this->assertEquals(83, $resp->json('efficiency_pct'));   // 2.5/3 = 83%
    }

    // ── M14 ──
    public function test_ocr_job_can_be_queued_and_processed(): void
    {
        \Queue::fake();
        $jobModel = \App\Models\Tenant\OcrJob::create([
            'company_id' => $this->company->id,
            'source_type' => 'pdf', 'file_path' => 'imports/test.pdf', 'status' => 'pending',
        ]);

        \App\Jobs\ProcessOcrJob::dispatch($jobModel->id, $this->company->id);
        \Queue::assertPushed(\App\Jobs\ProcessOcrJob::class, fn ($j) => $j->ocrJobId === $jobModel->id);
    }

    // ── M15 ──
    public function test_tracking_json_endpoint_returns_status_payload(): void
    {
        $client = Client::create(['name' => 'C', 'phone' => '+37399000000', 'type' => 'individual', 'status' => 'active']);
        $vehicle = Vehicle::create(['client_id' => $client->id, 'make' => 'BMW', 'model' => 'X5', 'plate' => 'JS-1']);
        $wo = WorkOrder::create([
            'number' => WorkOrder::generateNumber($this->company->id),
            'client_id' => $client->id, 'vehicle_id' => $vehicle->id,
            'opened_at' => today(), 'status' => 'in_work', 'total' => 500,
            'eta_promised' => now()->addHours(3),
            'eta_at' => now()->addHours(4),
            'eta_change_reason' => 'Aștept piesă',
        ]);

        $resp = $this->getJson("/api/track/{$wo->tracking_token}");
        $resp->assertOk();
        $this->assertEquals($wo->number, $resp->json('number'));
        $this->assertEquals('in_work', $resp->json('status'));
        $this->assertEquals('Aștept piesă', $resp->json('eta_change_reason'));
        $this->assertNotNull($resp->json('eta_promised'));
        $this->assertNotNull($resp->json('eta_current'));
    }

    public function test_tracking_json_returns_pending_approvals_with_signed_urls(): void
    {
        $client = Client::create(['name' => 'C', 'phone' => '+37399000000', 'type' => 'individual', 'status' => 'active']);
        $wo = WorkOrder::create(['number' => WorkOrder::generateNumber($this->company->id), 'client_id' => $client->id, 'opened_at' => today(), 'status' => 'in_work', 'total' => 0]);
        WorkOrderWork::create(['work_order_id' => $wo->id, 'name' => 'Needs OK', 'hours' => 1, 'price_per_hour' => 200, 'requires_approval' => true]);

        $resp = $this->getJson("/api/track/{$wo->tracking_token}");
        $resp->assertOk();
        $this->assertCount(1, $resp->json('pending_approvals'));
        $this->assertEquals('work', $resp->json('pending_approvals.0.kind'));
        $this->assertStringContainsString('/approve/work/', $resp->json('pending_approvals.0.approve_url'));
    }

    public function test_dispatcher_writes_notification_log_entry(): void
    {
        $client = Client::create(['name' => 'C', 'phone' => '+37399000000', 'email' => 'c@e.com', 'type' => 'individual', 'status' => 'active']);
        $wo = WorkOrder::create(['number' => WorkOrder::generateNumber($this->company->id), 'client_id' => $client->id, 'opened_at' => today(), 'closed_at' => today(), 'status' => 'ready', 'total' => 500]);
        \Mail::fake();

        app(\App\Services\NotificationDispatcher::class)->workOrderReady($wo);

        $log = ClientNotificationLog::where('work_order_id', $wo->id)->first();
        $this->assertNotNull($log);
        $this->assertEquals('wo_ready', $log->template_key);
        $this->assertContains($log->channel, ['email', 'telegram']);
        $this->assertEquals($wo->id, $log->work_order_id);
    }

    public function test_vehicle_body_and_transmission_round_trip(): void
    {
        $v = Vehicle::create(['client_id' => $this->makeClient()->id, 'make' => 'VW', 'model' => 'Tiguan', 'plate' => 'VR-1', 'body_type' => 'crossover', 'transmission_type' => 'dsg']);
        $fresh = Vehicle::find($v->id);
        $this->assertEquals('crossover', $fresh->body_type);
        $this->assertEquals('dsg', $fresh->transmission_type);
    }
}
