<?php

namespace App\Models;

use App\Enums\CashTransactionType;
use App\Models\Concerns\HasModuleMedia;
use App\Models\Concerns\InteractsWithActivityLog;
use Illuminate\Database\Eloquent\Attributes\Appends;
use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Attributes\Scope;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Spatie\MediaLibrary\HasMedia;

#[Guarded(['id'])]
#[Appends([
    'amount_formatted',
    'balance_after_formatted',
    'created_at_formatted',
    'created_by_name',
    'is_incoming',
    'reference_label',
    'source_badge_class',
])]
class CashTransaction extends Model implements HasMedia
{
    // 1. Use Trait
    use HasFactory, HasModuleMedia, InteractsWithActivityLog, SoftDeletes;

    // 2. Casting
    protected function casts(): array
    {
        return [
            'amount' => 'integer',
            'balance_after' => 'integer',
            'type' => CashTransactionType::class,
        ];
    }

    // 3. Scope (grouped by column, then alphabetical)
    // Column Group: type
    #[Scope]
    protected function deposit(Builder $query): void
    {
        $query->where('type', CashTransactionType::DEPOSIT);
    }

    #[Scope]
    protected function withdrawal(Builder $query): void
    {
        $query->where('type', CashTransactionType::WITHDRAWAL);
    }

    // 4. Attribute
    public function amountFormatted(): Attribute
    {
        return Attribute::make(
            get: fn () => 'Rp '.number_format($this->amount, 0, ',', '.'),
        );
    }

    public function balanceAfterFormatted(): Attribute
    {
        return Attribute::make(
            get: fn () => 'Rp '.number_format($this->balance_after, 0, ',', '.'),
        );
    }

    public function createdAtFormatted(): Attribute
    {
        return Attribute::make(
            get: fn () => $this->created_at?->translatedFormat('l, d F Y H:i'),
        );
    }

    public function createdByName(): Attribute
    {
        return Attribute::make(
            get: fn () => $this->createdBy?->profile?->full_name ?? $this->createdBy?->username,
        );
    }

    public function isIncoming(): Attribute
    {
        return Attribute::make(
            get: fn () => $this->reference_type === EmployeeAdvance::class
                ? $this->isEmployeeAdvanceRepayment()
                : $this->type === CashTransactionType::DEPOSIT,
        );
    }

    public function referenceLabel(): Attribute
    {
        return Attribute::make(
            get: function () {
                if ($this->reference_type === null) {
                    return $this->getManualTransactionLabel();
                }

                if ($this->reference_type === EmployeeAdvance::class) {
                    return $this->getEmployeeAdvanceLabel();
                }

                return self::labelForReferenceType($this->reference_type);
            },
        );
    }

    public function sourceBadgeClass(): Attribute
    {
        return Attribute::make(
            get: fn () => match ($this->reference_type) {
                null => 'bg-blue-100 text-blue-700 hover:bg-blue-100',
                Expense::class => 'bg-red-100 text-red-700 hover:bg-red-100',
                EmployeeAdvance::class => 'bg-amber-100 text-amber-700 hover:bg-amber-100',
                Payroll::class => 'bg-green-100 text-green-700 hover:bg-green-100',
                Order::class => 'bg-purple-100 text-purple-700 hover:bg-purple-100',
                default => 'bg-gray-100 text-gray-700 hover:bg-gray-100',
            },
        );
    }

    // 5. Other Methods
    public function getEmployeeAdvanceLabel(): string
    {
        return $this->isEmployeeAdvanceRepayment() ? 'Pelunasan Kasbon' : 'Pencairan Kasbon';
    }

    public function getManualTransactionLabel(): string
    {
        return $this->type === CashTransactionType::WITHDRAWAL ? 'Tarik Kas' : 'Setor Kas';
    }

    public function isEmployeeAdvanceRepayment(): bool
    {
        return $this->reference instanceof EmployeeAdvance
            && $this->reference->repayment_cash_transaction_id === $this->id;
    }

    public static function isIncomingTransaction(self $transaction): bool
    {
        return (bool) $transaction->is_incoming;
    }

    public static function labelForReferenceType(?string $referenceType): string
    {
        if ($referenceType === null) {
            return 'Setor Kas';
        }

        return match ($referenceType) {
            Expense::class => 'Pengeluaran',
            EmployeeAdvance::class => 'Kasbon Pegawai',
            Payroll::class => 'Gaji Pegawai',
            Order::class => 'Pesanan',
            default => class_basename($referenceType),
        };
    }

    public static function mediaModuleName(): string
    {
        return 'cash';
    }

    public function registerMediaCollections(): void
    {
        $this->addMediaCollection('photos');
    }

    // 6. Relation
    public function cashAccount(): BelongsTo
    {
        return $this->belongsTo(CashAccount::class);
    }

    public function createdBy(): BelongsTo
    {
        return $this->belongsTo(User::class, 'created_by_id');
    }

    public function order(): HasOne
    {
        return $this->hasOne(Order::class);
    }

    public function reference(): MorphTo
    {
        return $this->morphTo();
    }
}
