<?php

namespace App\Models\Warehouse\IndirectGoods;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\Models\Warehouse\Supplier;
use App\Models\Warehouse\Project;
use App\Models\Warehouse\ProjectDivision;
use App\Models\User;

class IndirectGoodsIncoming extends Model
{
    use HasFactory, SoftDeletes;

    protected $table = 'indirect_goods_incoming';

    protected $fillable = [
        'receipt_number',
        'receipt_date',
        'status',
        'supplier_id',
        'invoice_number',
        'invoice_date',
        'delivery_note_number',
        'project_id',
        'division_id',
        'total_amount',
        'vat_amount',
        'vat_rate',
        'currency',
        'delivery_file',
        'attached_documents',
        'received_by',
        'approved_by',
        'approved_at',
        'notes',
    ];

    protected $casts = [
        'receipt_date' => 'date',
        'invoice_date' => 'date',
        'total_amount' => 'decimal:2',
        'vat_amount' => 'decimal:2',
        'vat_rate' => 'decimal:2',
        'attached_documents' => 'array',
        'approved_at' => 'datetime',
    ];

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

        static::creating(function ($incoming) {
            if (empty($incoming->receipt_number)) {
                $incoming->receipt_number = static::generateReceiptNumber();
            }
        });
    }

    public static function generateReceiptNumber(): string
    {
        $prefix = 'IGR-' . date('Ymd') . '-';
        $last = static::withTrashed()
            ->where('receipt_number', 'LIKE', $prefix . '%')
            ->orderBy('receipt_number', 'desc')
            ->first();

        $seq = $last ? ((int) substr($last->receipt_number, -4) + 1) : 1;

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

    /**
     * Complete the incoming receipt and push items to inventory.
     */
    public function complete(): bool
    {
        if ($this->status === 'completed') {
            return false;
        }

        foreach ($this->items as $item) {
            $this->processItemToInventory($item);
        }

        $this->status = 'completed';
        $this->save();

        return true;
    }

    /**
     * Process a single incoming item to inventory.
     */
    protected function processItemToInventory(IndirectGoodsIncomingItem $incomingItem): void
    {
        $quantity = $incomingItem->quantity_accepted > 0
            ? $incomingItem->quantity_accepted
            : $incomingItem->quantity_delivered;

        if ($quantity <= 0) {
            return;
        }

        // Update warehouse inventory
        $inventory = IndirectGoodsInventory::firstOrNew([
            'indirect_good_id' => $incomingItem->indirect_good_id,
            'division_id' => $this->division_id,
            'batch_number' => $incomingItem->batch_number,
            'invoice_number' => $this->invoice_number,
        ]);

        if ($inventory->exists) {
            $inventory->updateQuantity($quantity, $incomingItem->unit_price, 'add');
        } else {
            $inventory->supplier_id = $this->supplier_id;
            $inventory->quantity_available = $quantity;
            $inventory->unit_price = $incomingItem->unit_price;
            $inventory->total_value = $quantity * $incomingItem->unit_price;
            $inventory->invoice_date = $this->invoice_date;
            $inventory->expiry_date = $incomingItem->expiry_date;
            $inventory->status = 'in_stock';
            $inventory->save();
        }

        // Update project inventory if project specified
        if ($this->project_id) {
            $projectInv = IndirectGoodsProjectInventory::firstOrNew([
                'project_id' => $this->project_id,
                'indirect_good_id' => $incomingItem->indirect_good_id,
                'invoice_number' => $this->invoice_number,
            ]);

            if ($projectInv->exists) {
                $projectInv->updateQuantity($quantity, $incomingItem->unit_price, 'add');
            } else {
                $projectInv->batch_number = $incomingItem->batch_number;
                $projectInv->quantity_available = $quantity;
                $projectInv->quantity_consumed = 0;
                $projectInv->unit_price = $incomingItem->unit_price;
                $projectInv->total_value = $quantity * $incomingItem->unit_price;
                $projectInv->save();
            }
        }

        // Create stock movement
        $totalBefore = IndirectGoodsInventory::where('indirect_good_id', $incomingItem->indirect_good_id)
            ->sum('quantity_available') - $quantity;

        IndirectGoodsStockMovement::create([
            'indirect_good_id' => $incomingItem->indirect_good_id,
            'movement_type' => 'in',
            'reference_type' => 'incoming',
            'reference_id' => $this->id,
            'quantity_before' => max(0, $totalBefore),
            'quantity_moved' => $quantity,
            'quantity_after' => $totalBefore + $quantity,
            'invoice_number' => $this->invoice_number,
            'division_id' => $this->division_id,
            'user_id' => $this->received_by,
            'notes' => 'Incoming receipt: ' . $this->receipt_number,
        ]);
    }

    // Relationships

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

    public function supplier()
    {
        return $this->belongsTo(Supplier::class, 'supplier_id');
    }

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

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

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

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