<?php

namespace App\Models;

use App\Models\Concerns\BelongsToBranch;
use App\Models\Concerns\HasAuditColumns;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;

class Account extends Model
{
    use BelongsToBranch;
    use HasAuditColumns;
    use SoftDeletes;

    protected $fillable = [
        'branch_id', 'code', 'name', 'type', 'parent_id',
        'opening_balance', 'is_active', 'is_system', 'cash_bank', 'description',
    ];

    protected function casts(): array
    {
        return ['opening_balance' => 'decimal:2', 'is_active' => 'boolean', 'is_system' => 'boolean'];
    }

    public const TYPES = ['asset', 'liability', 'equity', 'income', 'expense'];
    public const DEBIT_NORMAL = ['asset', 'expense'];

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

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

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

    public function isDebitNormal(): bool
    {
        return in_array($this->type, self::DEBIT_NORMAL, true);
    }

    /** Signed balance (debit positive). opening + Σ(debit − credit) up to a date. */
    public function signedBalance(?string $asOf = null): float
    {
        $q = $this->lines()->whereHas('entry', function ($e) use ($asOf) {
            if ($asOf) {
                $e->whereDate('date', '<=', $asOf);
            }
        });

        $net = (float) $q->sum('debit') - (float) $q->sum('credit');

        return round((float) $this->opening_balance + $net, 2);
    }

    /** Balance shown in the account's natural side (always non-negative for normal balances). */
    public function naturalBalance(?string $asOf = null): float
    {
        $signed = $this->signedBalance($asOf);

        return $this->isDebitNormal() ? $signed : -$signed;
    }

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

    public function scopeType(Builder $q, string $type): Builder
    {
        return $q->where('type', $type);
    }

    public function getLabelAttribute(): string
    {
        return $this->code.' — '.$this->name;
    }

    public function getTypeColorAttribute(): string
    {
        return [
            'asset' => 'primary', 'liability' => 'warning', 'equity' => 'info',
            'income' => 'success', 'expense' => 'danger',
        ][$this->type] ?? 'secondary';
    }
}
