<?php

namespace App\Services;

use App\Models\Caja;
use App\Models\CajaMovimiento;
use App\Models\OrdenLavanderia;
use App\Models\OrdenLavanderiaPago;
use Carbon\Carbon;
use Illuminate\Support\Collection;

class CajaCorteService
{
    /**
     * Efectivo esperado en caja al cierre del turno:
     * saldo inicial
     * + suma de montos en efectivo: por filas en `orden_lavanderia_pagos` con metodo efectivo,
     *   o si no hay filas, el total de la orden cuando metodo_pago = efectivo (órdenes legacy)
     * + movimientos manuales de ingreso
     * − movimientos de egreso (incluye devoluciones por cancelación de órdenes con venta_id).
     *
     * El saldo_final (negocio) sigue siendo saldo_inicial + total de ventas (todos los métodos);
     * no coincide con el efectivo físico cuando hay tarjeta/transferencia.
     */
    public function resumenParaCierre(Caja $caja, Carbon $hasta): array
    {
        $desde = $caja->abierto_at;

        /** @var Collection<int, OrdenLavanderia> $ventas */
        $ventas = OrdenLavanderia::query()
            ->where('caja_id', $caja->id)
            ->whereBetween('created_at', [$desde, $hasta])
            ->get();

        $totalVentas = (float) $ventas->sum('total');

        $porMetodoPago = [];
        $ventasEfectivo = 0.0;

        $pagosPorOrden = OrdenLavanderiaPago::query()
            ->whereIn('orden_lavanderia_id', $ventas->pluck('id')->all())
            ->get()
            ->groupBy('orden_lavanderia_id');

        foreach ($ventas as $v) {
            /** @var \Illuminate\Support\Collection<int, OrdenLavanderiaPago> $pagos */
            $pagos = $pagosPorOrden->get($v->id, collect());
            if ($pagos->isNotEmpty()) {
                foreach ($pagos as $p) {
                    $m = round((float) $p->monto, 2);
                    $mp = (string) $p->metodo_pago;
                    $porMetodoPago[$mp] = round(($porMetodoPago[$mp] ?? 0) + $m, 2);
                    if ($mp === 'efectivo') {
                        $ventasEfectivo += $m;
                    }
                }

                continue;
            }

            $t = round((float) $v->total, 2);
            if ($t <= 0) {
                continue;
            }
            $mp = $v->metodo_pago;
            if ($mp === null || $mp === '') {
                $porMetodoPago['sin_especificar'] = round(($porMetodoPago['sin_especificar'] ?? 0) + $t, 2);
            } else {
                $mp = (string) $mp;
                $porMetodoPago[$mp] = round(($porMetodoPago[$mp] ?? 0) + $t, 2);
                if ($mp === 'efectivo') {
                    $ventasEfectivo += $t;
                }
            }
        }

        $movimientos = CajaMovimiento::query()
            ->where('caja_id', $caja->id)
            ->whereBetween('created_at', [$desde, $hasta])
            ->get();

        $movimientosIngreso = (float) $movimientos
            ->where('tipo', CajaMovimiento::TIPO_INGRESO)
            ->sum('monto');

        $movimientosEgreso = (float) $movimientos
            ->where('tipo', CajaMovimiento::TIPO_EGRESO)
            ->sum('monto');

        $saldoFinal = (float) $caja->saldo_inicial + $totalVentas;

        $esperadoEfectivo = round(
            (float) $caja->saldo_inicial + $ventasEfectivo + $movimientosIngreso - $movimientosEgreso,
            2
        );

        return [
            'caja_id' => $caja->id,
            'caja_nombre' => $caja->nombre,
            'usuario' => $caja->usuario?->name ?? 'N/A',
            'abierto_at' => $desde->toIso8601String(),
            'cerrado_at' => $hasta->toIso8601String(),
            'saldo_inicial' => round((float) $caja->saldo_inicial, 2),
            'total_ventas' => round($totalVentas, 2),
            'saldo_final' => round($saldoFinal, 2),
            'por_metodo_pago' => $porMetodoPago,
            'cantidad_ventas' => $ventas->count(),
            'ventas_efectivo' => round($ventasEfectivo, 2),
            'movimientos_ingreso' => round($movimientosIngreso, 2),
            'movimientos_egreso' => round($movimientosEgreso, 2),
            'esperado_efectivo' => $esperadoEfectivo,
        ];
    }
}
