<?php

namespace App\Services;

use App\Models\Credit;
use App\Models\Expense;
use App\Models\FinancialOperation;
use App\Models\User;
use App\ValueObjects\Money;
use Illuminate\Support\Facades\DB;
use RuntimeException;

class FinancialOperationService
{
    /**
     * Extiende / refinancia un crédito existente
     *
     * Caso típico:
     * - Crédito viejo con saldo pendiente
     * - Se crea un crédito nuevo
     * - Parte del monto se compensa
     * - Solo el diferencial sale de caja
     */
    public function extendCredit(array $data, User $actor): FinancialOperation
    {
        return DB::transaction(function () use ($data, $actor) {

            /**
             * =========================
             * 1) Cargar y validar crédito origen
             * =========================
             */
            $sourceCredit = Credit::query()
                ->where('company_id', $actor->company_id)
                ->lockForUpdate()
                ->findOrFail($data['source_credit_id']);

            if (in_array($sourceCredit->status, [
                Credit::STATUS_CANCELED,
                Credit::STATUS_PAID,
            ])) {
                throw new RuntimeException(
                    'No se puede extender un crédito ya cerrado.'
                );
            }

            /**
             * =========================
             * 2) Calcular saldo pendiente real
             * =========================
             */
            $pendingAmount = $sourceCredit->installments()
                ->sum(DB::raw('total_amount - amount_paid'));

            if ($pendingAmount <= 0) {
                throw new RuntimeException(
                    'El crédito no tiene saldo pendiente para compensar.'
                );
            }

            $compensated = min($pendingAmount, $data['compensated_amount']);

            /**
             * =========================
             * 3) Crear crédito nuevo
             * =========================
             */
            $targetCredit = Credit::create([
                'company_id' => $actor->company_id,
                'client_id' => $sourceCredit->client_id,
                'amount' => $data['credit_amount'],
                'status' => Credit::STATUS_ACTIVE,
                'metadata' => [
                    'extended_from' => $sourceCredit->id,
                ],
            ]);

            /**
             * =========================
             * 4) Calcular caja real
             * =========================
             */
            $cashOut = Money::of($data['credit_amount'])
                ->subtract($compensated)
                ->value();

            if ($cashOut < 0) {
                throw new RuntimeException(
                    'El monto a desembolsar no puede ser negativo.'
                );
            }

            /**
             * =========================
             * 5) Registrar expense (solo si sale dinero)
             * =========================
             */
            $expense = null;

            if ($cashOut > 0) {
                $expense = Expense::create([
                    'company_id' => $actor->company_id,
                    'credit_id' => $targetCredit->id,
                    'user_id' => $actor->id,
                    'amount' => $cashOut,
                    'category' => 'disbursement',
                    'method' => $data['method'] ?? null,
                    'operation_date' => now(),
                    'notes' => 'Desembolso por extensión de crédito',
                    'metadata' => [
                        'source_credit_id' => $sourceCredit->id,
                        'compensated' => $compensated,
                    ],
                ]);
            }

            /**
             * =========================
             * 6) Marcar crédito anterior (lógico)
             * =========================
             */
            $sourceCredit->update([
                'status' => Credit::STATUS_PAID,
                'metadata' => array_merge(
                    $sourceCredit->metadata ?? [],
                    [
                        'extended_to' => $targetCredit->id,
                    ]
                ),
            ]);

            /**
             * =========================
             * 7) Registrar FinancialOperation
             * =========================
             */
            $operation = FinancialOperation::create([
                'company_id' => $actor->company_id,
                'user_id' => $actor->id,
                'operation_type' => 'credit_extension',
                'source_credit_id' => $sourceCredit->id,
                'target_credit_id' => $targetCredit->id,
                'credit_amount' => $data['credit_amount'],
                'compensated_amount' => $compensated,
                'cash_out' => $cashOut,
                'cash_in' => 0,
                'expense_id' => $expense?->id,
                'notes' => $data['notes'] ?? null,
            ]);

            return $operation;
        });
    }
}
