<?php

namespace App\Models;

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

class Budget extends Model
{
    use HasFactory;

    protected $fillable = [
        'user_id',
        'category_id',
        'subcategory_id',
        'cost_center_id',
        'name',
        'amount',
        'currency',
        'year',
        'month',
        'period_type',
        'is_cumulative',
        'is_active',
        'notes',
    ];

    protected $casts = [
        'amount' => 'decimal:2',
        'is_active' => 'boolean',
        'is_cumulative' => 'boolean',
    ];

    protected $appends = [
        'spent_amount',
        'remaining_amount',
        'usage_percentage',
        'is_exceeded',
        'period_label',
    ];

    // ============================================
    // Relaciones
    // ============================================

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

    public function category()
    {
        return $this->belongsTo(Category::class);
    }

    public function subcategory()
    {
        return $this->belongsTo(Category::class, 'subcategory_id');
    }

    public function costCenter()
    {
        return $this->belongsTo(CostCenter::class);
    }

    // ============================================
    // Accessors
    // ============================================

    public function getSpentAmountAttribute()
    {
        // Calcular el gasto real de las transacciones
        $query = Transaction::where('user_id', $this->user_id)
            ->where('type', 'debit');
        
        // Definir el rango de fechas según el tipo de período
        $startDate = Carbon::create($this->year, $this->month, 1);
        
        if ($this->is_cumulative) {
            // Cumulativo: desde el inicio del año hasta el final del período actual
            $endDate = $this->getPeriodEndDate();
            $query->whereYear('effective_date', $this->year)
                  ->whereDate('effective_date', '<=', $endDate);
        } else {
            // No cumulativo: solo el período específico
            switch ($this->period_type) {
                case 'monthly':
                    $query->whereYear('effective_date', $this->year)
                          ->whereMonth('effective_date', $this->month);
                    break;
                    
                case 'bimestral':
                    // 2 meses: mes actual + anterior (o siguiente según configuración)
                    $endDate = $startDate->copy()->addMonths(2)->subDay();
                    $query->whereBetween('effective_date', [$startDate, $endDate]);
                    break;
                    
                case 'trimestral':
                    // 3 meses
                    $endDate = $startDate->copy()->addMonths(3)->subDay();
                    $query->whereBetween('effective_date', [$startDate, $endDate]);
                    break;
                    
                case 'semestral':
                    // 6 meses
                    $endDate = $startDate->copy()->addMonths(6)->subDay();
                    $query->whereBetween('effective_date', [$startDate, $endDate]);
                    break;
                    
                case 'yearly':
                    $query->whereYear('effective_date', $this->year);
                    break;
            }
        }
        
        // Se tem subcategoria específica, usa apenas ela
        if ($this->subcategory_id) {
            $query->where('category_id', $this->subcategory_id);
        }
        // Se tem apenas categoria, inclui todas as subcategorias
        elseif ($this->category_id) {
            $categoryIds = [$this->category_id];
            $subcategories = Category::where('parent_id', $this->category_id)->pluck('id')->toArray();
            $categoryIds = array_merge($categoryIds, $subcategories);
            
            $query->whereIn('category_id', $categoryIds);
        }
        
        // Filtrar por centro de custos se especificado
        if ($this->cost_center_id) {
            $query->where('cost_center_id', $this->cost_center_id);
        }
        
        return abs($query->sum('amount'));
    }
    
    /**
     * Obtém a data final do período
     */
    private function getPeriodEndDate()
    {
        $startDate = Carbon::create($this->year, $this->month, 1);
        
        switch ($this->period_type) {
            case 'monthly':
                return $startDate->endOfMonth();
            case 'bimestral':
                return $startDate->copy()->addMonths(2)->subDay();
            case 'trimestral':
                return $startDate->copy()->addMonths(3)->subDay();
            case 'semestral':
                return $startDate->copy()->addMonths(6)->subDay();
            case 'yearly':
                return $startDate->endOfYear();
            default:
                return $startDate->endOfMonth();
        }
    }

    public function getRemainingAmountAttribute()
    {
        return $this->amount - $this->spent_amount;
    }

    public function getUsagePercentageAttribute()
    {
        if ($this->amount <= 0) return 0;
        return round(($this->spent_amount / $this->amount) * 100, 1);
    }

    public function getIsExceededAttribute()
    {
        return $this->spent_amount > $this->amount;
    }

    public function getPeriodLabelAttribute()
    {
        $months = [
            1 => 'Enero', 2 => 'Febrero', 3 => 'Marzo', 4 => 'Abril',
            5 => 'Mayo', 6 => 'Junio', 7 => 'Julio', 8 => 'Agosto',
            9 => 'Septiembre', 10 => 'Octubre', 11 => 'Noviembre', 12 => 'Diciembre'
        ];
        
        $monthName = $months[$this->month] ?? '';
        
        switch ($this->period_type) {
            case 'yearly':
                return $this->year;
            case 'bimestral':
                return $monthName . ' ' . $this->year . ' (Bimestral)';
            case 'trimestral':
                return $monthName . ' ' . $this->year . ' (Trimestral)';
            case 'semestral':
                return $monthName . ' ' . $this->year . ' (Semestral)';
            default:
                return $monthName . ' ' . $this->year;
        }
    }

    // ============================================
    // Methods
    // ============================================

    public static function copyToNextMonth($userId, $fromYear, $fromMonth)
    {
        $nextMonth = $fromMonth === 12 ? 1 : $fromMonth + 1;
        $nextYear = $fromMonth === 12 ? $fromYear + 1 : $fromYear;
        
        $budgets = self::where('user_id', $userId)
            ->where('year', $fromYear)
            ->where('month', $fromMonth)
            ->where('is_active', true)
            ->get();
        
        foreach ($budgets as $budget) {
            self::firstOrCreate([
                'user_id' => $userId,
                'category_id' => $budget->category_id,
                'year' => $nextYear,
                'month' => $nextMonth,
            ], [
                'name' => $budget->name,
                'amount' => $budget->amount,
                'currency' => $budget->currency,
                'period_type' => 'monthly',
                'is_active' => true,
            ]);
        }
    }

    // ============================================
    // Scopes
    // ============================================

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

    public function scopeForPeriod($query, $year, $month = null)
    {
        $query->where('year', $year);
        if ($month) {
            $query->where('month', $month);
        }
        return $query;
    }

    public function scopeForUser($query, $userId)
    {
        return $query->where('user_id', $userId);
    }
}
