<?php

namespace App\Models;

use App\Traits\MultiTenantScope;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Payment extends Model
{
    use MultiTenantScope;

    protected $fillable = [
        'company_id',
        'credit_id',
        'installment_id',
        'amount',
        'applied_amount',
        'extra_amount',
        'payment_date',
        'payment_method',
        'registered_by_user_id',
        'voided',
        'voided_by_user_id',
        'voided_at',
        'void_reason',
        'original_payment_id',
        // PWA fields
        'idempotency_key',
        'device_id',
        'offline_created_at',
        'latitude',
        'longitude',
    ];

    protected $casts = [
        'payment_date' => 'date',
        'voided_at' => 'datetime',
        'voided' => 'boolean',
        'amount' => 'decimal:2',
        'applied_amount' => 'decimal:2',
        'extra_amount' => 'decimal:2',
        'original_payment_id' => 'integer',
        'offline_created_at' => 'datetime',
        'latitude' => 'decimal:7',
        'longitude' => 'decimal:7',
    ];

    /*=========================================================
    | RELACIONES
    =========================================================*/
    public function company(): BelongsTo
    {
        return $this->belongsTo(Company::class);
    }

    /** @return BelongsTo<Credit, $this> */
    public function credit(): BelongsTo
    {
        return $this->belongsTo(Credit::class);
    }

    public function installment(): BelongsTo
    {
        return $this->belongsTo(Installment::class);
    }

    /** @return BelongsTo<User, $this> */
    public function registeredBy(): BelongsTo
    {
        return $this->belongsTo(User::class, 'registered_by_user_id');
    }

    /** @return BelongsToMany<Installment, $this> */
    public function installments(): BelongsToMany
    {
        return $this->belongsToMany(Installment::class, 'payment_installment')
            ->withPivot('applied_amount')
            ->withTimestamps();
    }

    public function auditLogs(): HasMany
    {
        return $this->hasMany(PaymentAuditLog::class, 'payment_id');
    }

    public function income()
    {
        return $this->hasOne(Income::class, 'payment_id');
    }

    /*=========================================================
    | SCOPES
    =========================================================*/

    /**
     * Pagos que representan dinero realmente recibido.
     *
     * Anular un pago deja DOS filas en la tabla: la original con `voided = 1`, y
     * una fila compensatoria de monto NEGATIVO con `payment_method = 'reversal'`
     * y `original_payment_id` apuntando a la original — que NO queda marcada como
     * anulada. Por eso filtrar solo por `voided = false` resta el monto dos veces:
     * excluye la original y encima suma el negativo.
     *
     * En produccion esto subestimaba los cobros: junio -$284.667, julio -$132.000,
     * agosto -$190.000. La caja (`incomes`) siempre estuvo bien, porque al anular
     * se borra el ingreso; el dano vivia solo en las sumas sobre `payments`.
     *
     * Se exigen los dos marcadores (metodo y FK) porque cuestan lo mismo y cubren
     * el caso de que uno se corrompa. Hoy coinciden exactamente.
     *
     * Para auditoria —ver que un pago fue anulado y por quien— NO usar este scope:
     * el panel de Filament muestra ambas filas a proposito.
     */
    public function scopeCollections(Builder $query): Builder
    {
        return $query
            ->where('voided', false)
            ->where('payment_method', '!=', 'reversal')
            ->whereNull('original_payment_id');
    }
}
