<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Tax extends Model
{
    use HasFactory;

    protected $fillable = [
        'name', 
        'rate', 
        'code',
        'description',
        'is_active',
        'is_default',
        'tax_type',
        'country_code',
        'state_code',
        'effective_from',
        'effective_to',
        'created_by',
        'updated_by'
    ];

    protected $casts = [
        'rate' => 'decimal:2',
        'is_active' => 'boolean',
        'is_default' => 'boolean',
        'effective_from' => 'datetime',
        'effective_to' => 'datetime',
    ];

    protected $appends = [
        'is_currently_effective',
        'display_rate',
    ];

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

        static::creating(function ($tax) {
            // Ensure only one default tax
            if ($tax->is_default) {
                static::where('is_default', true)->update(['is_default' => false]);
            }
            
            // Set created_by
            if (auth()->check()) {
                $tax->created_by = auth()->id();
            }
        });

        static::updating(function ($tax) {
            // Ensure only one default tax
            if ($tax->is_default) {
                static::where('is_default', true)
                    ->where('id', '!=', $tax->id)
                    ->update(['is_default' => false]);
            }
            
            // Set updated_by
            if (auth()->check()) {
                $tax->updated_by = auth()->id();
            }
        });
    }

    public function products(): HasMany
    {
        return $this->hasMany(Product::class);
    }

    public function saleItems(): HasMany
    {
        return $this->hasMany(SaleItem::class, 'tax_id');
    }

    /**
     * Scope for active taxes.
     */
    public function scopeActive($query)
    {
        return $query->where('is_active', true);
    }

    /**
     * Scope for default tax.
     */
    public function scopeDefault($query)
    {
        return $query->where('is_default', true);
    }

    /**
     * Scope for currently effective taxes.
     */
    public function scopeCurrentlyEffective($query)
    {
        $now = now();
        return $query->where(function($q) use ($now) {
            $q->whereNull('effective_from')
              ->orWhere('effective_from', '<=', $now);
        })->where(function($q) use ($now) {
            $q->whereNull('effective_to')
              ->orWhere('effective_to', '>=', $now);
        });
    }

    /**
     * Scope for VAT taxes.
     */
    public function scopeVat($query)
    {
        return $query->where('tax_type', 'vat');
    }

    /**
     * Scope for sales taxes.
     */
    public function scopeSalesTax($query)
    {
        return $query->where('tax_type', 'sales_tax');
    }

    /**
     * Scope for specific country.
     */
    public function scopeForCountry($query, $countryCode)
    {
        return $query->where('country_code', $countryCode);
    }

    /**
     * Check if tax is currently effective.
     */
    public function getIsCurrentlyEffectiveAttribute(): bool
    {
        $now = now();
        $fromValid = !$this->effective_from || $this->effective_from <= $now;
        $toValid = !$this->effective_to || $this->effective_to >= $now;
        
        return $fromValid && $toValid && $this->is_active;
    }

    /**
     * Get display rate with percentage.
     */
    public function getDisplayRateAttribute(): string
    {
        return $this->rate . '%';
    }

    /**
     * Calculate tax amount for a given price.
     */
    public function calculateAmount(float $price): float
    {
        return round($price * ($this->rate / 100), 2);
    }

    /**
     * Calculate price including tax.
     */
    public function calculatePriceIncludingTax(float $priceExcludingTax): float
    {
        return round($priceExcludingTax * (1 + ($this->rate / 100)), 2);
    }

    /**
     * Calculate price excluding tax.
     */
    public function calculatePriceExcludingTax(float $priceIncludingTax): float
    {
        return round($priceIncludingTax / (1 + ($this->rate / 100)), 2);
    }

    /**
     * Get default tax rate.
     */
    public static function getDefaultRate(): float
    {
        $defaultTax = static::default()->first();
        return $defaultTax ? (float) $defaultTax->rate : 0.00;
    }

    /**
     * Get applicable tax for a product/sale.
     */
    public static function getApplicableTax($product = null, $customer = null)
    {
        // Default to Kenya VAT
        $countryCode = 'KE';
        
        if ($customer && $customer->country_code) {
            $countryCode = $customer->country_code;
        }
        
        // Try to get active VAT tax for the country
        $tax = static::active()
            ->vat()
            ->forCountry($countryCode)
            ->currentlyEffective()
            ->first();
        
        // Fallback to default tax
        if (!$tax) {
            $tax = static::default()->first();
        }
        
        // Final fallback
        if (!$tax) {
            return new static([
                'name' => 'Standard VAT',
                'rate' => 16.00,
                'code' => 'VAT',
                'tax_type' => 'vat',
            ]);
        }
        
        return $tax;
    }

    /**
     * Validate tax data.
     */
    public static function validateData(array $data, $taxId = null): array
    {
        $rules = [
            'name' => 'required|string|max:255',
            'rate' => 'required|numeric|min:0|max:100',
            'code' => 'required|string|max:20|unique:taxes,code,' . ($taxId ?: 'NULL'),
            'tax_type' => 'required|in:vat,sales_tax,other',
            'country_code' => 'nullable|string|size:2',
            'is_active' => 'boolean',
            'is_default' => 'boolean',
            'effective_from' => 'nullable|date',
            'effective_to' => 'nullable|date|after_or_equal:effective_from',
        ];
        
        $messages = [
            'name.required' => 'Tax name is required',
            'rate.required' => 'Tax rate is required',
            'rate.max' => 'Tax rate cannot exceed 100%',
            'code.required' => 'Tax code is required',
            'code.unique' => 'Tax code already exists',
            'effective_to.after_or_equal' => 'Effective to date must be after or equal to effective from date',
        ];
        
        return [$rules, $messages];
    }

    /**
     * Get tax breakdown for display.
     */
    public function getBreakdown(float $amount): array
    {
        return [
            'tax_name' => $this->name,
            'tax_rate' => $this->rate,
            'tax_code' => $this->code,
            'taxable_amount' => $amount,
            'tax_amount' => $this->calculateAmount($amount),
            'total_with_tax' => $amount + $this->calculateAmount($amount),
        ];
    }

    /**
     * Check if tax can be deleted.
     */
    public function canBeDeleted(): array
    {
        if ($this->products()->exists()) {
            return [
                'can_delete' => false,
                'reason' => 'Tax is used by products'
            ];
        }
        
        if ($this->saleItems()->exists()) {
            return [
                'can_delete' => false,
                'reason' => 'Tax is used in sales'
            ];
        }
        
        if ($this->is_default) {
            return [
                'can_delete' => false,
                'reason' => 'Cannot delete default tax'
            ];
        }
        
        return ['can_delete' => true];
    }

    /**
     * Get tax statistics.
     */
    public function getStatistics($startDate = null, $endDate = null): array
    {
        $startDate = $startDate ?: now()->subMonth();
        $endDate = $endDate ?: now();
        
        $saleItems = $this->saleItems()
            ->whereHas('sale', function($query) use ($startDate, $endDate) {
                $query->whereBetween('sale_date', [$startDate, $endDate])
                      ->where('status', 'completed');
            })
            ->with('sale')
            ->get();
        
        $totalTaxable = $saleItems->sum(function($item) {
            return $item->quantity * $item->unit_price;
        });
        
        $totalTax = $saleItems->sum('tax_amount');
        $totalSales = $saleItems->count();
        
        return [
            'period' => [
                'start' => $startDate->format('Y-m-d'),
                'end' => $endDate->format('Y-m-d'),
            ],
            'tax' => [
                'name' => $this->name,
                'rate' => $this->rate,
                'code' => $this->code,
            ],
            'summary' => [
                'total_sales' => $totalSales,
                'total_taxable_amount' => $totalTaxable,
                'total_tax_collected' => $totalTax,
                'average_tax_per_sale' => $totalSales > 0 ? $totalTax / $totalSales : 0,
            ],
            'daily_breakdown' => $this->getDailyBreakdown($startDate, $endDate),
        ];
    }

    /**
     * Get daily tax breakdown.
     */
    private function getDailyBreakdown($startDate, $endDate): array
    {
        $breakdown = [];
        $currentDate = $startDate->copy();
        
        while ($currentDate <= $endDate) {
            $dailyItems = $this->saleItems()
                ->whereHas('sale', function($query) use ($currentDate) {
                    $query->whereDate('sale_date', $currentDate->format('Y-m-d'))
                          ->where('status', 'completed');
                })
                ->get();
            
            $breakdown[] = [
                'date' => $currentDate->format('Y-m-d'),
                'taxable_amount' => $dailyItems->sum(function($item) {
                    return $item->quantity * $item->unit_price;
                }),
                'tax_amount' => $dailyItems->sum('tax_amount'),
                'sales_count' => $dailyItems->groupBy('sale_id')->count(),
            ];
            
            $currentDate->addDay();
        }
        
        return $breakdown;
    }
}