<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Carbon\Carbon;

class Expense extends Model
{
    use HasFactory;

    protected $fillable = [
        'expense_number',
        'restaurant_id',
        'branch_id',
        'category_id',
        'user_id',
        'approved_by',
        'title',
        'description',
        'amount',
        'expense_date',
        'vendor',
        'receipt_number',
        'reference_number',
        'payment_method',
        'payment_status',
        'due_date',
        'payment_notes',
        'is_petty_cash',
        'petty_cash_balance_before',
        'petty_cash_balance_after',
        'priority',
        'status',
        'approval_notes',
        'approved_at',
        'paid_at',
        'attachments',
        'tags',
    ];

    protected $casts = [
        'amount' => 'decimal:2',
        'petty_cash_balance_before' => 'decimal:2',
        'petty_cash_balance_after' => 'decimal:2',
        'expense_date' => 'date',
        'due_date' => 'date',
        'approved_at' => 'datetime',
        'paid_at' => 'datetime',
        'attachments' => 'array',
        'tags' => 'array',
        'is_petty_cash' => 'boolean',
    ];

    protected static function boot()
    {
        parent::boot();
        
        static::creating(function ($expense) {
            if (!$expense->expense_number) {
                $expense->expense_number = static::generateExpenseNumber();
            }
        });
    }

    public function restaurant(): BelongsTo
    {
        return $this->belongsTo(Restaurant::class);
    }

    public function branch(): BelongsTo
    {
        return $this->belongsTo(Branch::class);
    }

    public function category(): BelongsTo
    {
        return $this->belongsTo(ExpenseCategory::class, 'category_id');
    }

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

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

    public function pettyCashTransactions()
    {
        return $this->hasMany(PettyCashTransaction::class);
    }

    // Scopes
    public function scopeForRestaurant($query, $restaurantId)
    {
        return $query->where('restaurant_id', $restaurantId);
    }

    public function scopeForBranch($query, $branchId)
    {
        return $query->where('branch_id', $branchId);
    }

    public function scopeByStatus($query, $status)
    {
        return $query->where('status', $status);
    }

    public function scopeByCategory($query, $categoryId)
    {
        return $query->where('category_id', $categoryId);
    }

    public function scopeByDateRange($query, $startDate, $endDate)
    {
        return $query->whereBetween('expense_date', [$startDate, $endDate]);
    }

    public function scopePending($query)
    {
        return $query->where('status', 'pending');
    }

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

    public function scopePaid($query)
    {
        return $query->where('status', 'paid');
    }

    public function scopePayLater($query)
    {
        return $query->where('payment_status', 'pay_later');
    }

    public function scopeImmediate($query)
    {
        return $query->where('payment_status', 'immediate');
    }

    public function scopePettyCash($query)
    {
        return $query->where('is_petty_cash', true);
    }

    public function scopeOverdue($query)
    {
        return $query->where('payment_status', 'pay_later')
                    ->where('due_date', '<', now())
                    ->whereNotIn('status', ['paid', 'rejected']);
    }

    public function scopeByPriority($query, $priority)
    {
        return $query->where('priority', $priority);
    }

    // Helper methods
    public function canBeApproved(): bool
    {
        return $this->status === 'pending';
    }

    public function canBeRejected(): bool
    {
        return $this->status === 'pending';
    }

    public function canBePaid(): bool
    {
        return $this->status === 'approved';
    }

    public function approve(User $approver, string $notes = null): bool
    {
        if (!$this->canBeApproved()) {
            return false;
        }

        $this->update([
            'status' => 'approved',
            'approved_by' => $approver->id,
            'approved_at' => now(),
            'approval_notes' => $notes,
        ]);

        return true;
    }

    public function reject(User $approver, string $notes = null): bool
    {
        if (!$this->canBeRejected()) {
            return false;
        }

        $this->update([
            'status' => 'rejected',
            'approved_by' => $approver->id,
            'approved_at' => now(),
            'approval_notes' => $notes,
        ]);

        return true;
    }

    public function markAsPaid(): bool
    {
        if (!$this->canBePaid()) {
            return false;
        }

        $this->update([
            'status' => 'paid',
            'paid_at' => now(),
        ]);

        return true;
    }

    public function getStatusColorAttribute(): string
    {
        return match($this->status) {
            'pending' => 'yellow',
            'approved' => 'green',
            'rejected' => 'red',
            'paid' => 'blue',
            default => 'gray',
        };
    }

    public function getStatusLabelAttribute(): string
    {
        return match($this->status) {
            'pending' => 'Pending Approval',
            'approved' => 'Approved',
            'rejected' => 'Rejected',
            'paid' => 'Paid',
            default => ucfirst($this->status),
        };
    }

    public static function generateExpenseNumber(): string
    {
        $prefix = 'EXP';
        $date = Carbon::now()->format('Ymd');
        $lastExpense = static::whereDate('created_at', Carbon::today())
            ->orderBy('id', 'desc')
            ->first();
        
        $sequence = $lastExpense ? 
            (int) substr($lastExpense->expense_number, -4) + 1 : 1;
        
        return $prefix . $date . str_pad($sequence, 4, '0', STR_PAD_LEFT);
    }

    public function hasAttachments(): bool
    {
        return !empty($this->attachments);
    }

    public function getAttachmentCount(): int
    {
        return count($this->attachments ?? []);
    }

    // New helper methods for enhanced functionality
    public function isPayLater(): bool
    {
        return $this->payment_status === 'pay_later';
    }

    public function isImmediate(): bool
    {
        return $this->payment_status === 'immediate';
    }

    public function isPettyCash(): bool
    {
        return $this->is_petty_cash === true;
    }

    public function isOverdue(): bool
    {
        return $this->isPayLater() && 
               $this->due_date && 
               $this->due_date->isPast() && 
               !in_array($this->status, ['paid', 'rejected']);
    }

    public function getDaysUntilDue(): ?int
    {
        if (!$this->due_date) return null;
        return now()->diffInDays($this->due_date, false);
    }

    public function getPriorityColorAttribute(): string
    {
        return match($this->priority) {
            'low' => 'gray',
            'medium' => 'blue',
            'high' => 'orange',
            'urgent' => 'red',
            default => 'gray',
        };
    }

    public function getPriorityLabelAttribute(): string
    {
        return match($this->priority) {
            'low' => 'Low Priority',
            'medium' => 'Medium Priority',
            'high' => 'High Priority',
            'urgent' => 'Urgent',
            default => ucfirst($this->priority),
        };
    }

    public function getPaymentStatusColorAttribute(): string
    {
        return match($this->payment_status) {
            'immediate' => 'green',
            'pay_later' => $this->isOverdue() ? 'red' : 'yellow',
            default => 'gray',
        };
    }

    public function getPaymentStatusLabelAttribute(): string
    {
        return match($this->payment_status) {
            'immediate' => 'Immediate Payment',
            'pay_later' => $this->isOverdue() ? 'Overdue' : 'Pay Later',
            default => ucfirst($this->payment_status),
        };
    }

    public function getFormattedAmountAttribute(): string
    {
        return 'KES ' . number_format($this->amount, 2);
    }

    public function canBeMarkedAsPaid(): bool
    {
        return in_array($this->status, ['approved']) || 
               ($this->status === 'pending' && $this->isPettyCash());
    }
}