<?php

namespace App\Models\Tenant;

use App\Models\Concerns\BelongsToTenant;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class WorkOrderWork extends Model
{
    use BelongsToTenant;

    protected $table = 'wo_works';

    protected $attributes = [
        'mechanic_status' => 'pending',
        'paused_seconds_total' => 0,
        'apply_margin' => true,
    ];

    public const STATUSES = [
        'todo' => 'De făcut',
        'in_progress' => 'În lucru',
        'done' => 'Finalizat',
    ];

    public const MECHANIC_STATUSES = [
        'pending' => 'În așteptare',
        'in_progress' => 'În lucru',
        'paused' => 'Pe pauză',
        'done' => 'Finalizat',
        'blocked' => 'Blocat',
    ];

    public const BLOCK_REASONS = [
        'missing_part' => 'Lipsă piesă',
        'awaiting_approval' => 'Aștept aprobare client',
        'broken_equipment' => 'Echipament defect',
        'other' => 'Altă problemă',
    ];

    protected $fillable = [
        'company_id', 'work_order_id', 'labor_id', 'master_id',
        'name', 'hours', 'price_per_hour', 'total', 'status', 'notes',
        'requires_approval', 'approved_at', 'approval_token', 'declined_at',
        'mechanic_status', 'mechanic_started_at', 'mechanic_done_at',
        'actual_hours', 'paused_seconds_total', 'paused_at',
        'block_reason', 'block_note',
        'salary_base', 'applied_margin_pct', 'apply_margin',
    ];

    protected $casts = [
        'hours' => 'decimal:2',
        'price_per_hour' => 'decimal:2',
        'total' => 'decimal:2',
        'requires_approval' => 'boolean',
        'approved_at' => 'datetime',
        'declined_at' => 'datetime',
        'mechanic_started_at' => 'datetime',
        'mechanic_done_at' => 'datetime',
        'paused_at' => 'datetime',
        'actual_hours' => 'decimal:2',
        'paused_seconds_total' => 'integer',
        'salary_base' => 'decimal:2',
        'applied_margin_pct' => 'decimal:2',
        'apply_margin' => 'boolean',
    ];

    // ── State machine ────────────────────────────────────────────
    public function start(): void
    {
        if ($this->mechanic_status === 'done') return;
        $this->forceFill([
            'mechanic_status' => 'in_progress',
            'mechanic_started_at' => $this->mechanic_started_at ?? now(),
            'paused_at' => null,
            'block_reason' => null,
            'block_note' => null,
            'status' => 'in_progress',
        ])->save();
    }

    public function pause(): void
    {
        if ($this->mechanic_status !== 'in_progress') return;
        $this->forceFill([
            'mechanic_status' => 'paused',
            'paused_at' => now(),
        ])->save();
    }

    public function resume(): void
    {
        if ($this->mechanic_status !== 'paused') return;
        $added = $this->paused_at ? $this->paused_at->diffInSeconds(now()) : 0;
        $this->forceFill([
            'mechanic_status' => 'in_progress',
            'paused_seconds_total' => (int) $this->paused_seconds_total + (int) $added,
            'paused_at' => null,
        ])->save();
    }

    public function markDone(): void
    {
        // If currently paused, count up till now as paused time before stopping.
        if ($this->mechanic_status === 'paused' && $this->paused_at) {
            $this->paused_seconds_total = (int) $this->paused_seconds_total + (int) $this->paused_at->diffInSeconds(now());
            $this->paused_at = null;
        }
        $started = $this->mechanic_started_at ?? now();
        $endedAt = now();
        $elapsedSec = max(0, $started->diffInSeconds($endedAt) - (int) $this->paused_seconds_total);
        $actualHours = round($elapsedSec / 3600, 2);

        $this->forceFill([
            'mechanic_status' => 'done',
            'mechanic_done_at' => $endedAt,
            'actual_hours' => $actualHours,
            'status' => 'done',
            'block_reason' => null,
        ])->save();
    }

    public function block(string $reason, ?string $note = null): void
    {
        if (! array_key_exists($reason, self::BLOCK_REASONS)) return;
        $this->forceFill([
            'mechanic_status' => 'blocked',
            'block_reason' => $reason,
            'block_note' => $note,
            'paused_at' => null,
        ])->save();
    }

    /** 'green' if faster than norm, 'amber' if 30%+ over, 'red' if 100%+ over. */
    public function efficiencyClass(): ?string
    {
        if ((float) $this->actual_hours <= 0 || (float) $this->hours <= 0) return null;
        $ratio = (float) $this->actual_hours / (float) $this->hours;
        return match (true) {
            $ratio <= 1.0 => 'green',
            $ratio <= 1.3 => 'amber',
            default => 'red',
        };
    }

    public function efficiencyPct(): ?int
    {
        if ((float) $this->actual_hours <= 0 || (float) $this->hours <= 0) return null;
        return (int) round(100 * (float) $this->actual_hours / (float) $this->hours);
    }

    public function isPendingApproval(): bool
    {
        return $this->requires_approval && $this->approved_at === null && $this->declined_at === null;
    }

    public function workOrder(): BelongsTo
    {
        return $this->belongsTo(WorkOrder::class);
    }

    public function labor(): BelongsTo
    {
        return $this->belongsTo(Labor::class);
    }

    public function master(): BelongsTo
    {
        return $this->belongsTo(User::class, 'master_id');
    }

    protected static function booted(): void
    {
        static::saving(function (self $row) {
            $row->total = round((float) $row->hours * (float) $row->price_per_hour, 2);
            if ($row->requires_approval && empty($row->approval_token)) {
                $row->approval_token = \Illuminate\Support\Str::random(24);
            }
            // Compute internal margin & freeze salary_base at save time.
            // Once frozen, changing user.internal_margin_pct later does NOT rewrite history.
            // WO.apply_margin=false → toate liniile Fișei devin at-cost (salariu pe Total).
            if (($row->salary_base === null || $row->isDirty(['total', 'master_id'])) && (float) $row->total > 0) {
                // Citim direct din DB pentru a evita orice cache al relației belongsTo
                $applyMargin = true;
                if ($row->work_order_id) {
                    $raw = \DB::table('work_orders')->where('id', $row->work_order_id)->value('apply_margin');
                    if ($raw !== null) $applyMargin = (bool) $raw;
                }
                if (! $applyMargin) {
                    $row->applied_margin_pct = 0;
                    $row->salary_base = (float) $row->total;
                } else {
                    $resolver = app(\App\Services\MarginResolver::class);
                    $mechanic = $row->master_id ? User::find($row->master_id) : null;
                    $wo = $row->workOrder;
                    $marginPct = $resolver->resolve($wo, $mechanic);
                    $row->applied_margin_pct = $marginPct;
                    $row->salary_base = $resolver->computeSalaryBase((float) $row->total, $marginPct);
                }
            }
        });
        static::saved(fn (self $row) => $row->workOrder?->recalcTotal());
        static::deleted(fn (self $row) => $row->workOrder?->recalcTotal());
    }
}
