<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use App\Models\Warehouse\Supplier;
use App\Models\Warehouse\Project;
use App\Models\Warehouse\ProjectDivision;
use App\Models\Warehouse\MaterialTransferRequest;
use App\Models\User;

class DirectDelivery extends Model
{
    protected $fillable = [
        'delivery_number',
        'reference_number', // For site returns linking
        'material_request_id', // Link to material request
        'material_request_number', // Original material request number
        'outgoing_transaction_id', // Link to original outgoing transaction
        'purchase_order_number',
        'supplier_delivery_note',
        'supplier_id',
        'project_id',
        'project_division_id',
        'project_phase',
        'site_location',
        'gps_coordinates',
        'delivery_date',
        'order_date',
        'delivered_by',
        'vehicle_number',
        'driver_contact',
        'status',
        'workflow_status',
        'delivery_type',
        'operation_type',
        'lpo_number',
        'lpo_status',
        'lpo_budget_amount',
        'total_amount',
        'total_amount_aed',
        'currency',
        'exchange_rate',
        'tax_amount',
        'vat_amount',
        'vat_rate',
        'discount_amount',
        'received_at',
        'received_by',
        'received_by_name',
        'receipt_notes',
        'receipt_document_path',
        'attached_documents',
        'photo_documentation',
        'delivery_notes',
        'delivery_instructions',
        'rejection_reason',
        'requires_approval',
        'approved_by',
        'approved_at',
        'approval_notes',
        'requires_inspection',
        'inspector_id',
        'inspection_datetime',
        'inspection_result',
        'inspection_notes',
        'inspection_checklist',
        'regulatory_compliant',
        'compliance_checklist',
        'can_be_returned', // Flag to indicate if items can be returned to site
        'project_inventory_updated' // Flag to track if project inventory has been updated
    ];

    protected $casts = [
        'delivery_date' => 'date',
        'order_date' => 'date',
        'expiry_date' => 'date',
        'warranty_expiry' => 'date',
        'received_at' => 'datetime',
        'approved_at' => 'datetime',
        'inspection_datetime' => 'datetime',
        'requires_approval' => 'boolean',
        'requires_inspection' => 'boolean',
        'regulatory_compliant' => 'boolean',
        'can_be_returned' => 'boolean',
        'project_inventory_updated' => 'boolean',
        'total_amount' => 'decimal:2',
        'total_amount_aed' => 'decimal:2',
        'lpo_budget_amount' => 'decimal:2',
        'exchange_rate' => 'decimal:4',
        'tax_amount' => 'decimal:2',
        'vat_amount' => 'decimal:2',
        'vat_rate' => 'decimal:2',
        'discount_amount' => 'decimal:2',
        'gps_coordinates' => 'json',
        'attached_documents' => 'json',
        'photo_documentation' => 'json',
        'inspection_checklist' => 'json',
        'compliance_checklist' => 'json'
    ];

    /**
     * Boot the model.
     */
    protected static function boot()
    {
        parent::boot();

        static::creating(function ($delivery) {
            $delivery->delivery_number = self::generateDeliveryNumber();
            $delivery->reference_number = self::generateReferenceNumber();

            // Default can_be_returned to true for received deliveries
            if ($delivery->can_be_returned === null) {
                $delivery->can_be_returned = true;
            }
        });
    }

    /**
     * Generate a unique delivery number.
     */
    public static function generateDeliveryNumber(): string
    {
        $prefix = 'DD'; // Direct Delivery
        $year = date('Y');
        $month = date('m');

        $lastDelivery = self::whereYear('created_at', $year)
            ->whereMonth('created_at', $month)
            ->orderBy('id', 'desc')
            ->first();

        $sequence = $lastDelivery ? intval(substr($lastDelivery->delivery_number, -4)) + 1 : 1;

        return sprintf('%s-%s%s-%04d', $prefix, $year, $month, $sequence);
    }

    /**
     * Generate a unique reference number for site returns.
     */
    public static function generateReferenceNumber(): string
    {
        $prefix = 'DDR'; // Direct Delivery Reference
        $year = date('Y');
        $month = date('m');
        $day = date('d');

        // Use a more detailed reference for returns
        $lastDelivery = self::whereDate('created_at', date('Y-m-d'))
            ->orderBy('id', 'desc')
            ->first();

        $sequence = $lastDelivery ? intval(substr($lastDelivery->reference_number, -3)) + 1 : 1;

        return sprintf('%s-%s%s%s-%03d', $prefix, $year, $month, $day, $sequence);
    }

    /**
     * Get the supplier for the delivery.
     */
    public function supplier(): BelongsTo
    {
        return $this->belongsTo(Supplier::class);
    }

    /**
     * Get the project for the delivery.
     */
    public function project(): BelongsTo
    {
        return $this->belongsTo(Project::class);
    }

    /**
     * Get the project division for the delivery.
     */
    public function projectDivision(): BelongsTo
    {
        return $this->belongsTo(ProjectDivision::class, 'project_division_id');
    }

    /**
     * Get the division for the delivery (using project_divisions table).
     */
    public function division(): BelongsTo
    {
        return $this->belongsTo(ProjectDivision::class, 'project_division_id');
    }


    /**
     * Get the user who received the delivery.
     */
    public function receivedBy(): BelongsTo
    {
        return $this->belongsTo(User::class, 'received_by');
    }

    /**
     * Get the user who approved the delivery.
     */
    public function approvedBy(): BelongsTo
    {
        return $this->belongsTo(User::class, 'approved_by');
    }

    /**
     * Get the user who inspected the delivery.
     */
    public function inspector(): BelongsTo
    {
        return $this->belongsTo(User::class, 'inspector_id');
    }

    /**
     * Get the material request associated with this delivery.
     */
    public function materialRequest(): BelongsTo
    {
        return $this->belongsTo(MaterialTransferRequest::class, 'material_request_id');
    }

    /**
     * Get the items for the delivery.
     */
    public function items(): HasMany
    {
        return $this->hasMany(DirectDeliveryItem::class);
    }

    /**
     * Mark the delivery as received.
     */
    public function markAsReceived($userId, $notes = null)
    {
        $this->update([
            'status' => 'received',
            'received_at' => now(),
            'received_by' => $userId,
            'receipt_notes' => $notes,
            'project_inventory_updated' => true
        ]);

        // Update project inventory
        $this->updateProjectInventory();

        // Create stock movements
        $this->createStockMovements();
    }

    /**
     * Mark the delivery as partially received.
     */
    public function markAsPartiallyReceived($userId, $notes = null)
    {
        $this->update([
            'status' => 'partially_received',
            'received_at' => now(),
            'received_by' => $userId,
            'receipt_notes' => $notes,
            'project_inventory_updated' => true
        ]);

        // Update project inventory for received items
        $this->updateProjectInventory();

        // Create stock movements for received items
        $this->createStockMovements();
    }

    /**
     * Update project inventory based on received items.
     */
    public function updateProjectInventory()
    {
        foreach ($this->items as $item) {
            // For direct deliveries, use received_quantity if available, otherwise use delivered_quantity
            $quantityToAdd = $item->received_quantity > 0 ? $item->received_quantity : $item->delivered_quantity;

            if ($quantityToAdd > 0) {
                // Update main inventory with full tracking information
                $inventory = \App\Models\Warehouse\Inventory::where('item_id', $item->item_id)
                    ->where('division_id', $this->project_division_id)
                    ->where('batch_number', $item->batch_number)
                    ->first();

                $deliveryStatus = match($this->status) {
                    'delivered' => 'delivered',
                    'received' => 'delivered',
                    'partially_delivered' => 'partially_delivered',
                    'partially_received' => 'partially_delivered',
                    default => 'dispatched'
                };

                if ($inventory) {
                    // Update existing inventory record
                    $inventory->update([
                        'quantity_available' => $inventory->quantity_available + $quantityToAdd,
                        'supplier_id' => $this->supplier_id,
                        'supplier_batch_number' => $item->supplier_batch_number,
                        'purchase_order_number' => $this->purchase_order_number,
                        'unit_price' => $item->unit_price ?: $inventory->unit_price,
                        'purchase_price' => $item->unit_price ?: $inventory->purchase_price,
                        'vat_amount' => $item->vat_amount ?: 0,
                        'currency' => $this->currency ?: 'AED',
                        'delivery_status' => $deliveryStatus,
                        'delivery_type' => 'direct_delivery',
                        'delivery_reference' => $this->delivery_number,
                        'delivered_at' => $this->status === 'delivered' || $this->status === 'received' ? now() : null,
                        'dispatched_at' => $this->delivery_date,
                        'quality_status' => $item->quality_status,
                        'quality_notes' => $item->quality_notes,
                        'compliance_verified' => $this->regulatory_compliant ?? false,
                        'expiry_date' => $item->expiry_date,
                        'production_date' => $item->production_date
                    ]);
                } else {
                    // Create new inventory record with all tracking information
                    \App\Models\Warehouse\Inventory::create([
                        'item_id' => $item->item_id,
                        'division_id' => $this->project_division_id,
                        'supplier_id' => $this->supplier_id,
                        'quantity_available' => $quantityToAdd,
                        'unit_price' => $item->unit_price ?: 0,
                        'purchase_price' => $item->unit_price ?: 0,
                        'vat_amount' => $item->vat_amount ?: 0,
                        'currency' => $this->currency ?: 'AED',
                        'total_value' => $quantityToAdd * ($item->unit_price ?: 0),
                        'location' => $this->site_location,
                        'batch_number' => $item->batch_number,
                        'supplier_batch_number' => $item->supplier_batch_number,
                        'purchase_order_number' => $this->purchase_order_number,
                        'production_date' => $item->production_date,
                        'expiry_date' => $item->expiry_date,
                        'status' => $quantityToAdd > 0 ? 'in_stock' : 'out_of_stock',
                        'delivery_status' => $deliveryStatus,
                        'delivery_type' => 'direct_delivery',
                        'delivery_reference' => $this->delivery_number,
                        'delivered_at' => $this->status === 'delivered' || $this->status === 'received' ? now() : null,
                        'dispatched_at' => $this->delivery_date,
                        'quality_status' => $item->quality_status,
                        'quality_notes' => $item->quality_notes,
                        'compliance_verified' => $this->regulatory_compliant ?? false
                    ]);
                }

                // Also update project inventory for project-specific tracking
                $projectInventory = \App\Models\Warehouse\ProjectInventory::where('project_id', $this->project_id)
                    ->where('item_id', $item->item_id)
                    ->first();

                if ($projectInventory) {
                    $projectInventory->updateQuantity($quantityToAdd, 'add');
                } else {
                    \App\Models\Warehouse\ProjectInventory::create([
                        'project_id' => $this->project_id,
                        'item_id' => $item->item_id,
                        'quantity_available' => $quantityToAdd,
                        'allocated_quantity' => 0,
                        'unit_price' => $item->unit_price ?: 0,
                        'total_value' => $quantityToAdd * ($item->unit_price ?: 0)
                    ]);
                }
            }
        }
    }

    /**
     * Create stock movements for the direct delivery.
     */
    public function createStockMovements()
    {
        foreach ($this->items as $item) {
            // For direct deliveries, use received_quantity if available, otherwise use delivered_quantity
            $quantityMoved = $item->received_quantity > 0 ? $item->received_quantity : $item->delivered_quantity;

            if ($quantityMoved > 0) {
                $now = now();
                $projectName = $this->project->project_name ?? 'Project #' . $this->project_id;

                // Stock IN - material received from supplier (attributed to division)
                \DB::table('stock_movements')->insert([
                    'item_id' => $item->item_id,
                    'division_id' => $this->project_division_id,
                    'movement_type' => 'in',
                    'quantity_before' => 0,
                    'quantity_moved' => $quantityMoved,
                    'quantity_after' => 0,
                    'reference_type' => 'App\Models\DirectDelivery',
                    'reference_id' => $this->id,
                    'notes' => "Direct delivery from supplier: " . ($this->supplier->name ?? 'Unknown') . " to project: " . $projectName,
                    'user_id' => $this->received_by ?? 1,
                    'created_at' => $now,
                    'updated_at' => $now
                ]);

                // Stock OUT - material issued from division to project site
                \DB::table('stock_movements')->insert([
                    'item_id' => $item->item_id,
                    'division_id' => $this->project_division_id,
                    'movement_type' => 'out',
                    'quantity_before' => 0,
                    'quantity_moved' => $quantityMoved,
                    'quantity_after' => 0,
                    'reference_type' => 'App\Models\DirectDelivery',
                    'reference_id' => $this->id,
                    'notes' => "Direct delivery issued to project: " . $projectName,
                    'user_id' => $this->received_by ?? 1,
                    'created_at' => $now->copy()->addSecond(),
                    'updated_at' => $now->copy()->addSecond()
                ]);
            }
        }
    }

    /**
     * Calculate the total value of the delivery.
     */
    public function calculateTotal()
    {
        $subtotal = $this->items->sum('total_price');
        $total = $subtotal + $this->tax_amount - $this->discount_amount;

        $this->update(['total_amount' => $total]);

        return $total;
    }

    /**
     * Get status color for badges.
     */
    public function getStatusColorAttribute(): string
    {
        return match($this->status) {
            'pending' => 'warning',
            'partially_delivered' => 'info',
            'partially_received' => 'info',
            'delivered' => 'success',
            'received' => 'success',
            'cancelled' => 'danger',
            default => 'secondary'
        };
    }

    /**
     * Get delivery type color for badges.
     */
    public function getDeliveryTypeColorAttribute(): string
    {
        return match($this->delivery_type) {
            'purchase_order' => 'primary',
            'direct_purchase' => 'info',
            'emergency' => 'danger',
            default => 'secondary'
        };
    }

    /**
     * Get formatted delivery type for display.
     */
    public function getDeliveryTypeDisplayAttribute(): string
    {
        return match($this->delivery_type) {
            'purchase_order' => 'Direct Delivery',
            'direct_purchase' => 'Direct Purchase',
            'emergency' => 'Emergency Delivery',
            default => ucfirst(str_replace('_', ' ', $this->delivery_type))
        };
    }

    /**
     * Calculate delivery status based on item quantities.
     */
    public function calculateDeliveryStatus(): string
    {
        $items = $this->items;

        if ($items->count() === 0) {
            return 'pending';
        }

        $totalOrdered = $items->sum('ordered_quantity');
        $totalDelivered = $items->sum('delivered_quantity');

        if ($totalDelivered == 0) {
            return 'pending';
        } elseif ($totalDelivered >= $totalOrdered) {
            return 'delivered';
        } else {
            return 'partially_delivered';
        }
    }

    /**
     * Update the status based on item delivery progress.
     */
    public function updateDeliveryStatus(): void
    {
        $calculatedStatus = $this->calculateDeliveryStatus();

        if ($this->status !== $calculatedStatus) {
            $oldStatus = $this->status;
            $this->update(['status' => $calculatedStatus]);

            // Update project inventory when status becomes 'delivered' or 'partially_delivered'
            if (in_array($calculatedStatus, ['delivered', 'partially_delivered']) &&
                !$this->project_inventory_updated) {
                $this->updateProjectInventory();
                $this->createStockMovements();
                $this->update(['project_inventory_updated' => true]);
            }
        }
    }

    /**
     * Check if delivery can be edited.
     */
    public function canEdit(): bool
    {
        return in_array($this->status, ['pending', 'partially_delivered']);
    }

    /**
     * Check if delivery can be received.
     */
    public function canReceive(): bool
    {
        return in_array($this->status, ['pending', 'partially_delivered', 'partially_received']);
    }

    /**
     * Check if delivery requires approval.
     */
    public function needsApproval(): bool
    {
        return $this->requires_approval && !$this->approved_at;
    }

    /**
     * Approve the delivery.
     */
    public function approve($userId, $notes = null)
    {
        $this->update([
            'approved_by' => $userId,
            'approved_at' => now(),
            'approval_notes' => $notes
        ]);
    }

    /**
     * Check if delivery items can be returned to site.
     */
    public function canBeReturned(): bool
    {
        return $this->can_be_returned &&
               $this->status === 'received' &&
               $this->items->where('received_quantity', '>', 0)->count() > 0;
    }

    /**
     * Get items that are eligible for return.
     */
    public function getReturnableItems()
    {
        return $this->items()->where('received_quantity', '>', 0)
                            ->where('quality_status', 'passed')
                            ->get();
    }

    /**
     * Create a site return record for this delivery.
     */
    public function createSiteReturn($returnData)
    {
        // This will create an incoming operation of type 'site_return'
        // that references this direct delivery via the reference_number
        $incomingOperation = \App\Models\Warehouse\IncomingOperation::create([
            'operation_number' => \App\Models\Warehouse\IncomingOperation::generateOperationNumber(),
            'operation_type' => 'site_return',
            'operation_date' => $returnData['return_date'] ?? now(),
            'status' => 'pending_inspection',

            // Link to this delivery
            'delivery_note_number' => $this->reference_number,
            'notes' => "Site return from direct delivery: {$this->delivery_number}",

            // Project and supplier info
            'project_id' => $this->project_id,
            'supplier_id' => $this->supplier_id,
            'division' => $returnData['division'] ?? null,

            // Return specific info
            'force_close_return' => $returnData['force_close'] ?? false,
            'force_close_reason' => $returnData['force_close_reason'] ?? null,

            // Financial
            'currency' => $this->currency,
            'total_amount' => 0, // Will be calculated from items
        ]);

        return $incomingOperation;
    }
}