<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\Models\Warehouse\Item;
use App\Models\Warehouse\Project;
use App\Models\Warehouse\IncomingOperation;
use App\Models\DamagedItem;
use App\Models\User;

class FocInventory extends Model
{
    use HasFactory, SoftDeletes;

    protected $table = 'foc_inventory';

    protected $fillable = [
        'item_id',
        'division_id',
        'quantity_available',
        'quantity_reserved',
        'unit',
        'source_type',
        'source_reference',
        'source_damaged_item_id',
        'source_project_id',
        'condition',
        'condition_notes',
        'damage_severity',
        'batch_number',
        'supplier_batch_number',
        'production_date',
        'expiry_date',
        'storage_location',
        'bin_location',
        'status',
        'quality_status',
        'quality_notes',
        'cost_responsibility',
        'estimated_value',
        'recoverable_value',
        'received_at',
        'last_dispatched_at',
        'created_by',
        'updated_by',
    ];

    protected $casts = [
        'quantity' => 'decimal:4',
        'quantity_available' => 'decimal:4',
        'quantity_reserved' => 'decimal:4',
        'unit_cost' => 'decimal:2',
        'total_cost' => 'decimal:2',
        'estimated_value' => 'decimal:2',
        'recoverable_value' => 'decimal:2',
        'recoverable_amount' => 'decimal:2',
        'production_date' => 'date',
        'expiry_date' => 'date',
        'approved_at' => 'datetime',
        'received_at' => 'datetime',
        'last_dispatched_at' => 'datetime',
    ];

    protected $dates = [
        'deleted_at',
        'received_at',
        'last_dispatched_at',
    ];

    // Relationships
    public function item()
    {
        return $this->belongsTo(Item::class);
    }

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

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

    public function sourceDamagedItem()
    {
        return $this->belongsTo(DamagedItem::class, 'source_damaged_item_id');
    }

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

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

    public function adjustments()
    {
        return $this->hasMany(FocInventoryAdjustment::class);
    }

    public function sourceIncomingOperation()
    {
        return $this->belongsTo(IncomingOperation::class, 'source_reference', 'operation_number');
    }

    // Scopes for common queries
    public function scopeAvailable($query)
    {
        // FOC inventory quantity_available IS the available quantity - no filtering needed
        return $query;
    }

    public function scopeForItem($query, $itemId)
    {
        return $query->where('item_id', $itemId);
    }

    public function scopeByCondition($query, $condition)
    {
        return $query->where('condition', $condition);
    }

    // Helper methods
    public function getNetAvailableQuantity()
    {
        return $this->quantity_available - $this->quantity_reserved;
    }

    public function reserve($quantity, $reason = null, $referenceType = null, $referenceId = null, $referenceNumber = null)
    {
        if ($quantity > $this->getNetAvailableQuantity()) {
            throw new \Exception('Insufficient FOC inventory to reserve');
        }

        $oldReserved = $this->quantity_reserved;
        $this->quantity_reserved += $quantity;
        $this->save();

        // Record adjustment
        $this->recordAdjustment([
            'adjustment_type' => 'reserve',
            'quantity_before' => $oldReserved,
            'quantity_after' => $this->quantity_reserved,
            'quantity_change' => $quantity,
            'reason' => $reason ?? 'Stock reserved for material issue',
            'reference_type' => $referenceType,
            'reference_id' => $referenceId,
            'reference_number' => $referenceNumber,
            'approval_status' => 'approved',
            'approved_by' => auth()->id() ?? 1,
            'approved_at' => now(),
        ]);

        return $this;
    }

    public function dispatch($quantity, $reason = null, $referenceType = null, $referenceId = null, $referenceNumber = null)
    {
        if ($quantity > $this->quantity_available) {
            throw new \Exception('Insufficient FOC inventory to dispatch');
        }

        $oldAvailable = $this->quantity_available;
        $oldReserved = $this->quantity_reserved;
        $oldStatus = $this->status;

        $this->quantity_available -= $quantity;
        $this->quantity_reserved = max(0, $this->quantity_reserved - $quantity);
        $this->last_dispatched_at = now();

        if ($this->quantity_available <= 0) {
            $this->status = 'dispatched';
        }

        $this->save();

        // Record adjustment
        $this->recordAdjustment([
            'adjustment_type' => 'dispatch',
            'quantity_before' => $oldAvailable,
            'quantity_after' => $this->quantity_available,
            'quantity_change' => -$quantity,
            'status_before' => $oldStatus,
            'status_after' => $this->status,
            'reason' => $reason ?? 'Stock dispatched for material issue',
            'reference_type' => $referenceType,
            'reference_id' => $referenceId,
            'reference_number' => $referenceNumber,
            'approval_status' => 'approved',
            'approved_by' => auth()->id() ?? 1,
            'approved_at' => now(),
        ]);

        return $this;
    }

    // New adjustment methods
    public function adjustQuantity($quantity, $reason, $referenceType = null, $referenceId = null, $referenceNumber = null)
    {
        $oldQuantity = $this->quantity_available;
        $newQuantity = $oldQuantity + $quantity;

        if ($newQuantity < 0) {
            throw new \Exception('Cannot reduce quantity below zero');
        }

        $this->quantity_available = $newQuantity;
        $this->save();

        $adjustmentType = $quantity > 0 ? 'stock_increase' : 'stock_decrease';

        return $this->recordAdjustment([
            'adjustment_type' => $adjustmentType,
            'quantity_before' => $oldQuantity,
            'quantity_after' => $newQuantity,
            'quantity_change' => $quantity,
            'reason' => $reason,
            'reference_type' => $referenceType,
            'reference_id' => $referenceId,
            'reference_number' => $referenceNumber,
        ]);
    }

    public function changeCondition($newCondition, $reason, $referenceType = null, $referenceId = null)
    {
        $oldCondition = $this->condition;
        $this->condition = $newCondition;
        $this->save();

        return $this->recordAdjustment([
            'adjustment_type' => 'condition_change',
            'quantity_before' => $this->quantity_available,
            'quantity_after' => $this->quantity_available,
            'quantity_change' => 0,
            'condition_before' => $oldCondition,
            'condition_after' => $newCondition,
            'reason' => $reason,
            'reference_type' => $referenceType,
            'reference_id' => $referenceId,
        ]);
    }

    public function dispose($quantity, $reason, $referenceType = null, $referenceId = null)
    {
        if ($quantity > $this->quantity_available) {
            throw new \Exception('Cannot dispose more than available quantity');
        }

        $oldQuantity = $this->quantity_available;
        $oldStatus = $this->status;

        $this->quantity_available -= $quantity;
        if ($this->quantity_available <= 0) {
            $this->status = 'disposed';
        }
        $this->save();

        return $this->recordAdjustment([
            'adjustment_type' => 'disposal',
            'quantity_before' => $oldQuantity,
            'quantity_after' => $this->quantity_available,
            'quantity_change' => -$quantity,
            'status_before' => $oldStatus,
            'status_after' => $this->status,
            'reason' => $reason,
            'reference_type' => $referenceType,
            'reference_id' => $referenceId,
            'cost_impact' => $this->estimated_value * ($quantity / $oldQuantity),
        ]);
    }

    private function recordAdjustment($data)
    {
        $adjustmentData = array_merge([
            'foc_inventory_id' => $this->id,
            'item_id' => $this->item_id,
            'requested_by' => auth()->id() ?? 1, // Default to user ID 1 if not authenticated
            'approval_status' => 'pending',
        ], $data);

        return FocInventoryAdjustment::create($adjustmentData);
    }

    // Static methods for bulk operations
    public static function getTotalAvailableForItem($itemId)
    {
        // quantity_available IS the FOC available - just sum it
        return static::forItem($itemId)->sum('quantity_available');
    }

    public static function getAvailableStockByItem()
    {
        // quantity_available IS the FOC available - just sum it
        return static::selectRaw('item_id, SUM(quantity_available) as total_available')
                    ->groupBy('item_id')
                    ->pluck('total_available', 'item_id');
    }

}