<?php

namespace App\Services;

use App\Models\Central\Company;
use App\Models\Tenant\Labor;
use App\Models\Tenant\Part;
use App\Models\Tenant\ServiceTemplate;
use App\Models\Tenant\WorkOrder;
use App\Models\Tenant\WorkOrderPart;
use App\Models\Tenant\WorkOrderWork;
use Illuminate\Support\Facades\DB;

/**
 * Composes work order lines from the labor catalog + templates:
 *   - adds a labor (hourly or fixed) and optionally its default parts
 *   - applies a full service template (labor + part lines) in one shot
 */
class ServiceComposer
{
    public function hourlyRate(int $companyId): float
    {
        $company = Company::withoutGlobalScopes()->find($companyId);
        return (float) data_get($company?->settings, 'labor_rate', 400);
    }

    /**
     * Add a labor line to a WO. Fixed-price labors set total directly via
     * hours=1 × price_per_hour=fixed_price. Returns the created work line.
     */
    public function addLabor(WorkOrder $wo, Labor $labor, bool $withParts = true): WorkOrderWork
    {
        $rate = $this->hourlyRate($wo->company_id);

        return DB::transaction(function () use ($wo, $labor, $withParts, $rate) {
            if ($labor->pricing_mode === 'fixed') {
                $hours = 1;
                $pricePerHour = (float) $labor->fixed_price;
            } else {
                $hours = (float) $labor->hours ?: 1;
                $pricePerHour = $rate;
            }

            $work = WorkOrderWork::create([
                'work_order_id' => $wo->id,
                'labor_id' => $labor->id,
                'name' => $labor->name_ro,
                'hours' => $hours,
                'price_per_hour' => $pricePerHour,
                'status' => 'todo',
            ]);

            if ($withParts) {
                foreach ($labor->laborParts as $lp) {
                    $part = $lp->part;
                    if (! $part) continue;
                    $this->addPart($wo, $part, (float) $lp->qty, $lp->unit ?: $part->unit);
                }
            }

            return $work;
        });
    }

    public function addPart(WorkOrder $wo, Part $part, float $qty, ?string $unit = null): WorkOrderPart
    {
        return WorkOrderPart::create([
            'work_order_id' => $wo->id,
            'part_id' => $part->id,
            'name' => $part->name,
            'article' => $part->article,
            'brand' => $part->brand,
            'qty' => $qty,
            'unit' => $unit ?: $part->unit ?: 'buc',
            'buy_price' => (float) $part->buy_price,
            'sell_price' => (float) $part->sell_price,
            'status' => 'needed',
        ]);
    }

    /**
     * Apply a full template to a WO: every labor + part item becomes a WO line.
     * Labor items are added WITHOUT their own default parts (template is explicit).
     *
     * @return array{labor:int, parts:int}
     */
    public function applyTemplate(WorkOrder $wo, ServiceTemplate $template): array
    {
        return DB::transaction(function () use ($wo, $template) {
            $laborCount = 0;
            $partCount = 0;

            foreach ($template->items as $item) {
                if ($item->kind === 'labor') {
                    if ($item->labor_id && ($labor = Labor::find($item->labor_id))) {
                        $work = $this->addLabor($wo, $labor, withParts: false);
                        if ($item->hours) {
                            $work->hours = (float) $item->hours;
                            $work->save();
                        }
                    } else {
                        // Free-text labor line from snapshot.
                        WorkOrderWork::create([
                            'work_order_id' => $wo->id,
                            'name' => $item->name,
                            'hours' => (float) ($item->hours ?: 1),
                            'price_per_hour' => $this->hourlyRate($wo->company_id),
                            'status' => 'todo',
                        ]);
                    }
                    $laborCount++;
                } elseif ($item->kind === 'part') {
                    if ($item->part_id && ($part = Part::find($item->part_id))) {
                        $this->addPart($wo, $part, (float) ($item->qty ?: 1));
                    } else {
                        WorkOrderPart::create([
                            'work_order_id' => $wo->id,
                            'name' => $item->name,
                            'qty' => (float) ($item->qty ?: 1),
                            'unit' => 'buc',
                            'sell_price' => 0,
                            'status' => 'needed',
                        ]);
                    }
                    $partCount++;
                }
            }

            $wo->recalcTotal();

            return ['labor' => $laborCount, 'parts' => $partCount];
        });
    }
}
