<?php

namespace App\Models;

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

class Account extends Model
{
    use HasFactory, SoftDeletes;

    protected $fillable = [
        'code',
        'name',
        'type',
        'sub_type',
        'parent_id',
        'opening_balance',
        'opening_type',
        'current_balance',
        'description',
        'is_system',
        'is_active',
    ];

    protected $casts = [
        'opening_balance' => 'decimal:2',
        'current_balance' => 'decimal:2',
        'is_system' => 'boolean',
        'is_active' => 'boolean',
    ];

    /**
     * Account types with their normal balance side
     */
    public const TYPES = [
        'asset' => ['label' => 'Assets', 'normal_balance' => 'debit'],
        'liability' => ['label' => 'Liabilities', 'normal_balance' => 'credit'],
        'equity' => ['label' => 'Equity', 'normal_balance' => 'credit'],
        'income' => ['label' => 'Income', 'normal_balance' => 'credit'],
        'expense' => ['label' => 'Expenses', 'normal_balance' => 'debit'],
    ];

    /**
     * Sub types for dropdown
     */
    public const SUB_TYPES = [
        'asset' => [
            'cash' => 'Cash',
            'bank' => 'Bank',
            'receivable' => 'Accounts Receivable',
            'inventory' => 'Inventory',
            'fixed_asset' => 'Fixed Assets',
            'other_asset' => 'Other Assets',
        ],
        'liability' => [
            'payable' => 'Accounts Payable',
            'loan' => 'Loans',
            'accrued' => 'Accrued Expenses',
            'other_liability' => 'Other Liabilities',
        ],
        'equity' => [
            'capital' => 'Capital',
            'retained_earnings' => 'Retained Earnings',
            'drawing' => 'Drawings',
        ],
        'income' => [
            'sales' => 'Sales Revenue',
            'service_income' => 'Service Income',
            'other_income' => 'Other Income',
        ],
        'expense' => [
            'purchase' => 'Purchases',
            'salary' => 'Salary Expense',
            'rent' => 'Rent Expense',
            'utility' => 'Utility Expense',
            'transport' => 'Transport Expense',
            'office' => 'Office Expense',
            'other_expense' => 'Other Expense',
        ],
    ];

    /**
     * Parent account relationship
     */
    public function parent(): BelongsTo
    {
        return $this->belongsTo(Account::class, 'parent_id');
    }

    /**
     * Child accounts relationship
     */
    public function children(): HasMany
    {
        return $this->hasMany(Account::class, 'parent_id');
    }

    /**
     * Transactions relationship
     */
    public function transactions(): HasMany
    {
        return $this->hasMany(Transaction::class);
    }

    /**
     * Parties linked to this account
     */
    public function parties(): HasMany
    {
        return $this->hasMany(Party::class);
    }

    /**
     * Get the normal balance side for this account type
     */
    public function getNormalBalanceAttribute(): string
    {
        return self::TYPES[$this->type]['normal_balance'] ?? 'debit';
    }

    /**
     * Get formatted balance with Dr/Cr suffix
     */
    public function getFormattedBalanceAttribute(): string
    {
        $balance = abs($this->current_balance);
        $suffix = $this->current_balance >= 0 ? 'Dr' : 'Cr';
        
        if ($this->normal_balance === 'credit') {
            $suffix = $this->current_balance >= 0 ? 'Cr' : 'Dr';
        }
        
        return number_format($balance, 2) . ' ' . $suffix;
    }

    /**
     * Update the current balance from transactions
     */
    public function updateBalance(): void
    {
        $debit = $this->transactions()->sum('debit');
        $credit = $this->transactions()->sum('credit');
        
        // For debit-normal accounts (Assets, Expenses): Balance = Debit - Credit
        // For credit-normal accounts (Liabilities, Equity, Income): Balance = Credit - Debit
        if ($this->normal_balance === 'debit') {
            $this->current_balance = $this->opening_balance + $debit - $credit;
        } else {
            $this->current_balance = $this->opening_balance + $credit - $debit;
        }
        
        $this->save();
    }

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

    /**
     * Scope by type
     */
    public function scopeOfType($query, string $type)
    {
        return $query->where('type', $type);
    }

    /**
     * Scope for cash accounts
     */
    public function scopeCash($query)
    {
        return $query->where('sub_type', 'cash');
    }

    /**
     * Scope for bank accounts
     */
    public function scopeBank($query)
    {
        return $query->where('sub_type', 'bank');
    }

    /**
     * Scope for cash and bank accounts
     */
    public function scopeCashAndBank($query)
    {
        return $query->whereIn('sub_type', ['cash', 'bank']);
    }

    /**
     * Generate next account code
     */
    public static function generateCode(string $type): string
    {
        $prefixes = [
            'asset' => '1',
            'liability' => '2',
            'equity' => '3',
            'income' => '4',
            'expense' => '5',
        ];

        $prefix = $prefixes[$type] ?? '9';
        $lastAccount = self::where('code', 'like', $prefix . '%')
            ->orderBy('code', 'desc')
            ->first();

        if ($lastAccount) {
            $lastNumber = intval(substr($lastAccount->code, 1));
            return $prefix . str_pad($lastNumber + 1, 4, '0', STR_PAD_LEFT);
        }

        return $prefix . '0001';
    }
}
