<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use App\Models\Warehouse\Item;
use App\Models\User;

class DirectDeliveryItem extends Model
{
    protected $fillable = [
        'direct_delivery_id',
        'material_request_item_id',
        'item_id',
        'quantity_ordered',
        'quantity_delivered',
        'quantity_accepted',
        'quantity_rejected',
        'ordered_quantity',
        'delivered_quantity',
        'received_quantity',
        'rejected_quantity',
        'returned_quantity', // Track quantity returned from site
        'quantity_transferred',
        'transfer_status',
        'unit_of_measure',
        'unit_price',
        'total_price',
        'currency',
        'unit_price_aed',
        'total_price_aed',
        'tax_rate',
        'tax_amount',
        'vat_rate',
        'vat_amount',
        'discount_rate',
        'discount_amount',
        'batch_number',
        'supplier_batch_number',
        'serial_number',
        'manufacturing_date',
        'production_date',
        'expiry_date',
        'manufacturer',
        'country_of_origin',
        'item_description',
        'specifications',
        'quality_status',
        'quality_notes',
        'quality_checklist',
        'quality_checked_at',
        'quality_checked_by',
        'storage_location',
        'storage_conditions',
        'hazardous_material',
        'hazard_classifications',
        'warranty_period_months',
        'warranty_expiry',
        'requires_maintenance',
        'maintenance_interval_days',
        'allocated_project_id',
        'project_phase',
        'work_area',
        'status',
        'rack_number',
        'bin_number',
        'receipt_notes',
        'rejection_reason',
        'can_be_returned' // Item level return flag
    ];

    protected $casts = [
        'quantity_ordered' => 'decimal:2',
        'quantity_delivered' => 'decimal:2',
        'quantity_accepted' => 'decimal:2',
        'quantity_rejected' => 'decimal:2',
        'ordered_quantity' => 'decimal:2',
        'delivered_quantity' => 'decimal:2',
        'received_quantity' => 'decimal:2',
        'rejected_quantity' => 'decimal:2',
        'returned_quantity' => 'decimal:2',
        'quantity_transferred' => 'decimal:2',
        'transfer_status' => 'string',
        'unit_price' => 'decimal:2',
        'unit_price_aed' => 'decimal:2',
        'total_price' => 'decimal:2',
        'total_price_aed' => 'decimal:2',
        'tax_rate' => 'decimal:2',
        'tax_amount' => 'decimal:2',
        'discount_rate' => 'decimal:2',
        'discount_amount' => 'decimal:2',
        'can_be_returned' => 'boolean',
        'hazardous_material' => 'boolean',
        'requires_maintenance' => 'boolean',
        'manufacturing_date' => 'date',
        'expiry_date' => 'date',
        'warranty_expiry' => 'date',
        'quality_checked_at' => 'datetime',
        'quality_checklist' => 'json',
        'hazard_classifications' => 'json'
    ];

    /**
     * Get the direct delivery for this item.
     */
    public function directDelivery(): BelongsTo
    {
        return $this->belongsTo(DirectDelivery::class);
    }

    /**
     * Get the item.
     */
    public function item(): BelongsTo
    {
        return $this->belongsTo(Item::class);
    }

    /**
     * Get the user who checked quality.
     */
    public function qualityCheckedBy(): BelongsTo
    {
        return $this->belongsTo(User::class, 'quality_checked_by');
    }

    /**
     * Calculate total price based on quantity and unit price.
     */
    public function calculateTotal()
    {
        $subtotal = $this->received_quantity * $this->unit_price;

        // Calculate tax
        $taxAmount = $subtotal * ($this->tax_rate / 100);

        // Calculate discount
        $discountAmount = $subtotal * ($this->discount_rate / 100);

        // Calculate final total
        $total = $subtotal + $taxAmount - $discountAmount;

        $this->update([
            'tax_amount' => $taxAmount,
            'discount_amount' => $discountAmount,
            'total_price' => $total
        ]);

        return $total;
    }

    /**
     * Mark item as quality checked.
     */
    public function markQualityChecked($status, $userId, $notes = null)
    {
        $this->update([
            'quality_status' => $status,
            'quality_checked_at' => now(),
            'quality_checked_by' => $userId,
            'quality_notes' => $notes
        ]);
    }

    /**
     * Get the variance between delivered and received quantities.
     */
    public function getQuantityVarianceAttribute()
    {
        return $this->delivered_quantity - $this->received_quantity;
    }

    /**
     * Get the variance percentage.
     */
    public function getVariancePercentageAttribute()
    {
        if ($this->delivered_quantity == 0) {
            return 0;
        }

        return round((($this->delivered_quantity - $this->received_quantity) / $this->delivered_quantity) * 100, 2);
    }

    /**
     * Check if item has been fully received.
     */
    public function isFullyReceived(): bool
    {
        return $this->received_quantity >= $this->delivered_quantity;
    }

    /**
     * Check if item has been partially received.
     */
    public function isPartiallyReceived(): bool
    {
        return $this->received_quantity > 0 && $this->received_quantity < $this->delivered_quantity;
    }

    /**
     * Get remaining quantity that can still be delivered.
     */
    public function getRemainingDeliverableQuantity(): float
    {
        return max(0, $this->ordered_quantity - $this->delivered_quantity);
    }

    /**
     * Get delivery completion percentage.
     */
    public function getDeliveryCompletionPercentage(): float
    {
        if ($this->ordered_quantity == 0) {
            return 0;
        }

        return round(($this->delivered_quantity / $this->ordered_quantity) * 100, 2);
    }

    /**
     * Check if item has been fully delivered.
     */
    public function isFullyDelivered(): bool
    {
        return $this->delivered_quantity >= $this->ordered_quantity;
    }

    /**
     * Check if item has been partially delivered.
     */
    public function isPartiallyDelivered(): bool
    {
        return $this->delivered_quantity > 0 && $this->delivered_quantity < $this->ordered_quantity;
    }

    /**
     * Get delivery status description.
     */
    public function getDeliveryStatusDescription(): string
    {
        if ($this->delivered_quantity == 0) {
            return 'Not Delivered';
        } elseif ($this->isFullyDelivered()) {
            return 'Fully Delivered';
        } else {
            return 'Partially Delivered';
        }
    }

    /**
     * Get quality status color for badges.
     */
    public function getQualityStatusColorAttribute(): string
    {
        return match($this->quality_status) {
            'pending' => 'warning',
            'passed' => 'success',
            'failed' => 'danger',
            'partial' => 'info',
            default => 'secondary'
        };
    }

    /**
     * Check if this item can be returned to site.
     */
    public function canBeReturned(): bool
    {
        // Check if there's any quantity (received, delivered, or ordered)
        $hasQuantity = ($this->received_quantity > 0 || $this->delivered_quantity > 0 || $this->ordered_quantity > 0);

        return $this->can_be_returned &&
               $hasQuantity &&
               $this->getAvailableForReturnQuantity() > 0;
    }

    /**
     * Get quantity available for return (received - already returned).
     */
    public function getAvailableForReturnQuantity(): float
    {
        // For items delivered directly to project sites, use delivered_quantity
        // For items formally received at warehouse, use received_quantity
        // If neither is available, use ordered_quantity (for pending deliveries)
        $baseQuantity = $this->received_quantity > 0 ? $this->received_quantity : $this->delivered_quantity;

        // For pending deliveries where delivered_quantity is 0, use ordered_quantity
        if ($baseQuantity <= 0) {
            $baseQuantity = $this->ordered_quantity ?? 0;
        }

        return $baseQuantity - ($this->returned_quantity ?? 0);
    }

    /**
     * Get return status text.
     */
    public function getReturnStatusAttribute(): string
    {
        if (!$this->can_be_returned) {
            return 'Not Returnable';
        }

        $available = $this->getAvailableForReturnQuantity();

        if ($available <= 0) {
            return 'Fully Returned';
        }

        if ($this->returned_quantity > 0) {
            return 'Partially Returned';
        }

        return 'Available for Return';
    }

    /**
     * Record a return for this item.
     */
    public function recordReturn(float $quantity, ?string $reason = null): void
    {
        if ($quantity > $this->getAvailableForReturnQuantity()) {
            throw new \InvalidArgumentException('Return quantity exceeds available quantity');
        }

        $this->increment('returned_quantity', $quantity);

        // If all received quantity is returned, mark as not returnable
        if ($this->getAvailableForReturnQuantity() <= 0) {
            $this->can_be_returned = false;
            $this->save();
        }
    }
}