<?php

namespace App\Models;

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

class MoneyMarketAccount extends Model
{
    protected $fillable = [
        'membership_id',
        'account_number',
        'principal_amount',
        'interest_rate',
        'term_months',
        'start_date',
        'maturity_date',
        'interest_earned',
        'total_amount',
        'status',
        'currency_code',
        'notes',
        'withdrawn_at',
        'withdrawal_amount',
        'interest_type', // simple, compound
        'compounding_frequency', // monthly, quarterly, annually
        'last_interest_update',
    ];

    protected $casts = [
        'principal_amount' => 'decimal:2',
        'interest_rate' => 'decimal:2',
        'interest_earned' => 'decimal:2',
        'total_amount' => 'decimal:2',
        'withdrawal_amount' => 'decimal:2',
        'start_date' => 'date',
        'maturity_date' => 'date',
        'withdrawn_at' => 'datetime',
        'last_interest_update' => 'datetime',
    ];

    /**
     * Relationship with Membership
     */
    public function membership(): BelongsTo
    {
        return $this->belongsTo(Membership::class);
    }

    /**
     * Relationship with Transactions
     */
    public function transactions()
    {
        return $this->hasMany(Transaction::class, 'reference_id')->where('type', 'money_market');
    }

    /**
     * Generate unique account number
     */
    public static function generateAccountNumber(): string
    {
        do {
            $accountNumber = 'MMA' . date('Y') . str_pad(mt_rand(1, 999999), 6, '0', STR_PAD_LEFT);
        } while (self::where('account_number', $accountNumber)->exists());

        return $accountNumber;
    }

    /**
     * Calculate interest earned based on interest type
     */
    public function calculateInterest(): float
    {
        $interestType = $this->interest_type ?? 'simple';
        $compoundingFrequency = $this->compounding_frequency ?? 'annually';

        if ($interestType === 'compound') {
            return $this->calculateCompoundInterest($compoundingFrequency);
        }

        return $this->calculateSimpleInterest();
    }

    /**
     * Calculate simple interest
     */
    public function calculateSimpleInterest(): float
    {
        $daysElapsed = Carbon::now()->diffInDays($this->start_date);
        $yearsElapsed = $daysElapsed / 365;

        // Simple interest calculation: Principal * Rate * Time
        return $this->principal_amount * ($this->interest_rate / 100) * $yearsElapsed;
    }

    /**
     * Calculate compound interest
     */
    public function calculateCompoundInterest(string $frequency = 'annually'): float
    {
        $principal = $this->principal_amount;
        $rate = $this->interest_rate / 100;
        $startDate = $this->start_date;
        $currentDate = Carbon::now();

        // Determine compounding periods per year
        $compoundsPerYear = match($frequency) {
            'monthly' => 12,
            'quarterly' => 4,
            'annually' => 1,
            default => 1,
        };

        $yearsElapsed = $startDate->diffInDays($currentDate) / 365;

        // Compound interest formula: P(1 + r/n)^(nt)
        $amount = $principal * pow(1 + ($rate / $compoundsPerYear), $compoundsPerYear * $yearsElapsed);

        return $amount - $principal;
    }

    /**
     * Calculate interest for a specific period
     */
    public function calculateInterestForPeriod(Carbon $fromDate, Carbon $toDate): float
    {
        $interestType = $this->interest_type ?? 'simple';
        $compoundingFrequency = $this->compounding_frequency ?? 'annually';

        if ($interestType === 'compound') {
            return $this->calculateCompoundInterestForPeriod($fromDate, $toDate, $compoundingFrequency);
        }

        return $this->calculateSimpleInterestForPeriod($fromDate, $toDate);
    }

    /**
     * Calculate simple interest for a specific period
     */
    private function calculateSimpleInterestForPeriod(Carbon $fromDate, Carbon $toDate): float
    {
        $daysInPeriod = $fromDate->diffInDays($toDate);
        $yearsInPeriod = $daysInPeriod / 365;

        return $this->principal_amount * ($this->interest_rate / 100) * $yearsInPeriod;
    }

    /**
     * Calculate compound interest for a specific period
     */
    private function calculateCompoundInterestForPeriod(Carbon $fromDate, Carbon $toDate, string $frequency): float
    {
        $principal = $this->principal_amount;
        $rate = $this->interest_rate / 100;

        $compoundsPerYear = match($frequency) {
            'monthly' => 12,
            'quarterly' => 4,
            'annually' => 1,
            default => 1,
        };

        $yearsInPeriod = $fromDate->diffInDays($toDate) / 365;

        $amount = $principal * pow(1 + ($rate / $compoundsPerYear), $compoundsPerYear * $yearsInPeriod);

        return $amount - $principal;
    }

    /**
     * Calculate maturity amount
     */
    public function calculateMaturityAmount(): float
    {
        return $this->principal_amount + $this->calculateInterest();
    }

    /**
     * Check if account is matured
     */
    public function isMatured(): bool
    {
        return Carbon::now()->gte($this->maturity_date);
    }

    /**
     * Get days until maturity
     */
    public function daysUntilMaturity(): int
    {
        return Carbon::now()->diffInDays($this->maturity_date, false);
    }

    /**
     * Get account status badge color
     */
    public function getStatusBadgeClass(): string
    {
        return match($this->status) {
            'active' => 'badge-success',
            'matured' => 'badge-warning',
            'withdrawn' => 'badge-info',
            'cancelled' => 'badge-danger',
            default => 'badge-secondary',
        };
    }

    /**
     * Scope for active accounts
     */
    public function scopeActive($query)
    {
        return $query->where('status', 'active');
    }

    /**
     * Scope for matured accounts
     */
    public function scopeMatured($query)
    {
        return $query->where('status', 'matured');
    }

    /**
     * Scope for accounts nearing maturity (within 30 days)
     */
    public function scopeNearingMaturity($query)
    {
        return $query->where('maturity_date', '<=', Carbon::now()->addDays(30))
                    ->where('status', 'active');
    }

    /**
     * Update interest earned
     */
    public function updateInterestEarned(): void
    {
        $this->interest_earned = $this->calculateInterest();
        $this->total_amount = $this->calculateMaturityAmount();
        $this->last_interest_update = now();
        $this->save();
    }

    /**
     * Update interest periodically (for compound interest)
     */
    public function updatePeriodicInterest(): void
    {
        if ($this->interest_type !== 'compound' || $this->status !== 'active') {
            return;
        }

        $frequency = $this->compounding_frequency ?? 'annually';
        $lastUpdate = $this->last_interest_update ?? $this->start_date;

        $shouldUpdate = match($frequency) {
            'monthly' => $lastUpdate->diffInMonths(now()) >= 1,
            'quarterly' => $lastUpdate->diffInMonths(now()) >= 3,
            'annually' => $lastUpdate->diffInYears(now()) >= 1,
            default => false,
        };

        if ($shouldUpdate) {
            $interestEarned = $this->calculateInterestForPeriod($lastUpdate, now());
            $this->interest_earned += $interestEarned;
            $this->total_amount = $this->principal_amount + $this->interest_earned;
            $this->last_interest_update = now();

            // Log the interest accrual transaction
            $this->logTransaction('interest_accrual', $interestEarned, 'Interest accrued on money market account');

            $this->save();
        }
    }

    /**
     * Log a transaction for this account
     */
    public function logTransaction(string $type, float $amount, string $description = null): void
    {
        Transaction::create([
            'user_id' => $this->membership->user_id,
            'type' => 'money_market_' . $type,
            'amount' => $amount,
            'reference_id' => $this->id,
            'reference_type' => 'money_market_account',
            'description' => $description ?? ucfirst(str_replace('_', ' ', $type)) . ' - ' . $this->account_number,
            'status' => 'completed',
            'currency_code' => $this->currency_code,
        ]);
    }

    /**
     * Mark as matured
     */
    public function markAsMatured(): void
    {
        if ($this->isMatured() && $this->status === 'active') {
            $this->updateInterestEarned();
            $this->status = 'matured';
            $this->save();
        }
    }

    /**
     * Withdraw investment
     */
    public function withdraw(float $amount = null): bool
    {
        if ($this->status !== 'active' && $this->status !== 'matured') {
            return false;
        }

        $withdrawalAmount = $amount ?? $this->total_amount;

        if ($withdrawalAmount > $this->total_amount) {
            return false; // Cannot withdraw more than available
        }

        $this->withdrawal_amount = $withdrawalAmount;
        $this->withdrawn_at = now();
        $this->status = 'withdrawn';

        // Log the withdrawal transaction
        $this->logTransaction('withdrawal', -$withdrawalAmount, 'Withdrawal from money market account');

        $this->save();

        return true;
    }
}
