<?php

namespace App\Models\Warehouse\FixedAssets;

use App\Models\User;
use App\Models\Warehouse\Project;
use App\Models\Warehouse\ProjectDivision;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\DB;

class FixedAssetAllocation extends Model
{
    use HasFactory, SoftDeletes;

    protected $table = 'fixed_asset_allocations';

    protected $fillable = [
        'allocation_number',
        'allocation_date',
        'destination_type',
        'project_id',
        'division_id',
        'requested_by',
        'approved_by',
        'approved_at',
        'allocated_by',
        'allocated_at',
        'purpose',
        'notes',
        'status',
        'rejection_reason',
    ];

    protected $casts = [
        'allocation_date' => 'date',
        'approved_at' => 'datetime',
        'allocated_at' => 'datetime',
    ];

    protected static function boot()
    {
        parent::boot();

        static::creating(function ($model) {
            if (empty($model->allocation_number)) {
                $model->allocation_number = static::generateAllocationNumber();
            }
        });
    }

    /**
     * Generate a unique allocation number.
     */
    public static function generateAllocationNumber(): string
    {
        return DB::transaction(function () {
            $prefix = 'FAA-' . now()->format('Ymd') . '-';

            $lastRecord = static::withTrashed()
                ->where('allocation_number', 'like', $prefix . '%')
                ->orderBy('allocation_number', 'desc')
                ->lockForUpdate()
                ->first();

            if ($lastRecord) {
                $lastNumber = (int) substr($lastRecord->allocation_number, -4);
                $newNumber = $lastNumber + 1;
            } else {
                $newNumber = 1;
            }

            return $prefix . str_pad($newNumber, 4, '0', STR_PAD_LEFT);
        });
    }

    /**
     * Approve the allocation request.
     */
    public function approve(int $userId): void
    {
        $this->update([
            'status' => 'approved',
            'approved_by' => $userId,
            'approved_at' => now(),
        ]);
    }

    /**
     * Reject the allocation request.
     */
    public function reject(int $userId, string $reason): void
    {
        $this->update([
            'status' => 'rejected',
            'approved_by' => $userId,
            'approved_at' => now(),
            'rejection_reason' => $reason,
        ]);
    }

    /**
     * Resolve destination details based on destination_type.
     */
    public function resolveDestination(): array
    {
        $destinationType = $this->destination_type ?? 'project';

        if ($destinationType === 'repair_shop') {
            return [
                'lifecycle_status' => 'under_maintenance',
                'location'         => 'Repair Shop',
                'project_id'       => null,
                'division_id'      => null,
                'movement_type'    => 'maintenance_start',
            ];
        }

        if ($destinationType === 'warehouse') {
            return [
                'lifecycle_status' => 'in_warehouse',
                'location'         => 'Warehouse',
                'project_id'       => null,
                'division_id'      => null,
                'movement_type'    => 'return',
            ];
        }

        // default: project
        return [
            'lifecycle_status' => 'in_use',
            'location'         => $this->project ? $this->project->project_name : 'Project',
            'project_id'       => $this->project_id,
            'division_id'      => $this->division_id,
            'movement_type'    => 'allocation',
        ];
    }

    /**
     * Allocate assets to the destination.
     */
    public function allocate(int $userId): void
    {
        DB::transaction(function () use ($userId) {
            $dest = $this->resolveDestination();

            foreach ($this->items as $item) {
                $item->update([
                    'is_allocated' => true,
                    'allocated_at' => now(),
                ]);

                $asset = $item->fixedAsset;
                $fromLocation   = $asset->current_location ?: 'Warehouse';
                $fromProjectId  = $asset->current_project_id;
                $fromDivisionId = $asset->current_division_id;
                $statusBefore   = $asset->lifecycle_status;
                $conditionBefore = $asset->condition;

                $asset->update([
                    'lifecycle_status'    => $dest['lifecycle_status'],
                    'current_project_id'  => $dest['project_id'],
                    'current_division_id' => $dest['division_id'],
                    'current_location'    => $dest['location'],
                ]);

                FixedAssetMovement::create([
                    'fixed_asset_id'         => $asset->id,
                    'movement_type'          => $dest['movement_type'],
                    'from_location'          => $fromLocation,
                    'to_location'            => $dest['location'],
                    'from_project_id'        => $fromProjectId,
                    'to_project_id'          => $dest['project_id'],
                    'from_division_id'       => $fromDivisionId,
                    'to_division_id'         => $dest['division_id'],
                    'condition_before'       => $conditionBefore,
                    'condition_after'        => $asset->condition,
                    'lifecycle_status_before' => $statusBefore,
                    'lifecycle_status_after' => $dest['lifecycle_status'],
                    'movement_date'          => now(),
                    'reference_type'         => 'allocation',
                    'reference_id'           => $this->id,
                    'performed_by'           => $userId,
                    'notes'                  => 'Asset allocated via ' . $this->allocation_number,
                ]);
            }

            $this->update([
                'status'       => 'allocated',
                'allocated_by' => $userId,
                'allocated_at' => now(),
            ]);
        });
    }

    // ── Relationships ──────────────────────────────────────────────────

    public function items()
    {
        return $this->hasMany(FixedAssetAllocationItem::class, 'fixed_asset_allocation_id');
    }

    public function project()
    {
        return $this->belongsTo(Project::class);
    }

    public function division()
    {
        return $this->belongsTo(ProjectDivision::class, 'division_id');
    }

    public function requester()
    {
        return $this->belongsTo(User::class, 'requested_by');
    }

    public function approvedBy()
    {
        return $this->belongsTo(User::class, 'approved_by');
    }

    public function allocatedBy()
    {
        return $this->belongsTo(User::class, 'allocated_by');
    }

    // ── Scopes ─────────────────────────────────────────────────────────

    public function scopePendingApproval(Builder $query): Builder
    {
        return $query->where('status', 'pending_approval');
    }

    public function scopeApproved(Builder $query): Builder
    {
        return $query->where('status', 'approved');
    }
}
