<?php

namespace App\Http\Controllers\Caja;

use App\Http\Controllers\Controller;
use App\Models\Caja\AperturaCierre;
use Barryvdh\DomPDF\Facade\Pdf;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;

class CierreController extends Controller
{
    public function index()
    {
        $user = auth()->user();
        $id_sede = $user ? $user->id_sede : null;
        $id_usuario = $user ? $user->id : null;

        if (is_null($id_sede) || (int) $id_sede <= 0) {
            abort(403, 'No puede acceder: no tiene una sede asignada.');
        }

        $sede = DB::table('sedes')
            ->where('id', $id_sede)
            ->select('id', 'sede as sede_nombre')
            ->first();

        $apertura = DB::table('apertura_cierre')
            ->where('id_sede', $id_sede)
            ->where('id_usuario_apertura', $id_usuario)
            ->where('estado', 'ABIERTO')
            ->orderByDesc('id')
            ->first();

        if (!$apertura) {
            return view('Caja.cierre.index', [
                'sede' => $sede,
                'apertura' => null,
                'fechaHora' => now(),
                'saldoInicial' => 0,
                'ingresos' => 0,
                'egresos' => 0,
                'saldoTeorico' => 0,
            ]);
        }

        $totales = DB::table('movimientos')
            ->selectRaw("
                COALESCE(SUM(CASE WHEN tipo_movimiento = 1 AND estado <> 'AN' THEN monto ELSE 0 END), 0) as ingresos,
                COALESCE(SUM(CASE WHEN tipo_movimiento = 2 AND estado <> 'AN' THEN monto ELSE 0 END), 0) as egresos
            ")
            ->where('id_sede', $id_sede)
            ->where('id_usuario', $id_usuario)
            ->where('id_apertura_cierre', $apertura->id)
            ->first();

        $saldoInicial = (float) $apertura->saldo_inicial;
        $ingresos = (float) ($totales->ingresos ?? 0);
        $egresos = (float) ($totales->egresos ?? 0);
        $saldoTeorico = $saldoInicial + $ingresos - $egresos;

        return view('Caja.cierre.index', [
            'sede' => $sede,
            'apertura' => $apertura,
            'fechaHora' => now(),
            'saldoInicial' => $saldoInicial,
            'ingresos' => $ingresos,
            'egresos' => $egresos,
            'saldoTeorico' => $saldoTeorico,
        ]);
    }

    public function create()
    {
        return redirect()->route('admin.cierre.index');
    }

    public function store(Request $request)
    {
        $user = auth()->user();
        $id_sede = $user ? $user->id_sede : null;
        $id_usuario = $user ? $user->id : null;

        if (is_null($id_sede) || (int) $id_sede <= 0) {
            abort(403, 'No puede acceder: no tiene una sede asignada.');
        }

        $apertura = AperturaCierre::query()
            ->where('id_sede', $id_sede)
            ->where('id_usuario_apertura', $id_usuario)
            ->where('estado', 'ABIERTO')
            ->orderByDesc('id')
            ->first();

        if (!$apertura) {
            return redirect()
                ->route('admin.cierre.index')
                ->with('error', 'No existe una caja abierta para cerrar.');
        }

        $totales = DB::table('movimientos')
            ->selectRaw("
                COALESCE(SUM(CASE WHEN tipo_movimiento = 1 AND estado <> 'AN' THEN monto ELSE 0 END), 0) as ingresos,
                COALESCE(SUM(CASE WHEN tipo_movimiento = 2 AND estado <> 'AN' THEN monto ELSE 0 END), 0) as egresos
            ")
            ->where('id_sede', $id_sede)
            ->where('id_usuario', $id_usuario)
            ->where('id_apertura_cierre', $apertura->id)
            ->first();

        $saldoInicial = (float) $apertura->saldo_inicial;
        $ingresos = (float) ($totales->ingresos ?? 0);
        $egresos = (float) ($totales->egresos ?? 0);
        $saldoTeorico = $saldoInicial + $ingresos - $egresos;

        $data = $request->validate([
            'saldo_real' => ['required', 'numeric', 'min:0'],
            'observacion_cierre' => ['nullable', 'string', 'max:255'],
            'fecha_hora_cliente' => ['nullable', 'date_format:Y-m-d H:i:s'],
        ], [
            'saldo_real.required' => 'El saldo real es obligatorio.',
            'saldo_real.numeric' => 'El saldo real debe ser numerico.',
            'saldo_real.min' => 'El saldo real no puede ser menor a 0.',
            'observacion_cierre.max' => 'La observacion no debe exceder 255 caracteres.',
        ]);

        $saldoReal = (float) $data['saldo_real'];
        $diferencia = $saldoReal - $saldoTeorico;
        $fechaCierre = !empty($data['fecha_hora_cliente'])
            ? Carbon::createFromFormat('Y-m-d H:i:s', $data['fecha_hora_cliente'])
            : now();

        $apertura->update([
            'id_usuario_cierre' => $id_usuario,
            'fecha_cierre' => $fechaCierre,
            'ingresos' => $ingresos,
            'egresos' => $egresos,
            'saldo_teorico' => $saldoTeorico,
            'saldo_real' => $saldoReal,
            'diferencia' => $diferencia,
            'estado' => 'CERRADO',
            'observacion_cierre' => isset($data['observacion_cierre']) && trim($data['observacion_cierre']) !== ''
                ? trim($data['observacion_cierre'])
                : '',
            'updated_at' => $fechaCierre,
        ]);

        $this->guardarPdfCierre($apertura->id);

        return redirect()
            ->route('admin.cierre.index')
            ->with('success', 'Caja cerrada correctamente.')
            ->with('cierre_fecha_hora', $fechaCierre->format('d/m/Y H:i:s'))
            ->with('cierre_saldo_real', number_format($saldoReal, 2, '.', ''))
            ->with('pdf_link', route('admin.cierre.pdf', $apertura->id))
            ->with('pdf_filename', $this->nombreArchivoPdfCierre($apertura));
    }

    public function pdf(string $id)
    {
        $archivo = $this->guardarPdfCierre($id);

        return response()->file($archivo, [
            'Content-Type' => 'application/pdf',
        ]);
    }

    private function guardarPdfCierre($aperturaId)
    {
        $item = AperturaCierre::query()->findOrFail($aperturaId);

        $sede = DB::table('sedes')
            ->where('id', $item->id_sede)
            ->select('sede')
            ->first();

        $usuario = DB::table('users')
            ->where('id', $item->id_usuario_cierre ?: $item->id_usuario_apertura)
            ->select('name', 'username', 'dni')
            ->first();

        $parametros = DB::table('parametro_comprobante')
            ->where('id_sede', $item->id_sede)
            ->first();

        $data = [
            'titulo' => 'COMPROBANTE DE CIERRE DE CAJA',
            'encabezado' => $parametros->encabezado ?? 'SEMINARIO',
            'direccion' => $parametros->direccion ?? '',
            'imagen' => $parametros->imagen ?? null,
            'sede' => $sede->sede ?? '',
            'fecha_hora' => Carbon::parse($item->fecha_cierre ?: $item->updated_at ?: now())->format('d/m/Y H:i:s'),
            'usuario' => !empty($usuario->name) ? $usuario->name : ($usuario->username ?? ''),
            'dni' => $usuario->dni ?? '',
            'estado' => $item->estado,
            'campos' => [
                'Saldo inicial' => number_format((float) $item->saldo_inicial, 2, '.', ','),
                'Ingresos' => number_format((float) $item->ingresos, 2, '.', ','),
                'Egresos' => number_format((float) $item->egresos, 2, '.', ','),
                'Saldo teorico' => number_format((float) $item->saldo_teorico, 2, '.', ','),
                'Saldo real' => number_format((float) $item->saldo_real, 2, '.', ','),
                'Diferencia' => number_format((float) $item->diferencia, 2, '.', ','),
                'Observacion' => (string) ($item->observacion_cierre ?? ''),
            ],
        ];

        $dir = public_path('recibo_apertura_cierre');
        if (!File::exists($dir)) {
            File::makeDirectory($dir, 0755, true);
        }

        $nombreArchivo = $this->nombreArchivoPdfCierre($item);
        $rutaArchivo = $dir . DIRECTORY_SEPARATOR . $nombreArchivo;

        Pdf::loadView('PDF.CierreCaja', $data)
            ->setPaper('A4', 'portrait')
            ->save($rutaArchivo);

        return $rutaArchivo;
    }

    private function nombreArchivoPdfCierre($item): string
    {
        return 'CIERRE_CAJA_' . $item->id . '_' . Carbon::parse($item->fecha_cierre ?: $item->updated_at ?: now())->format('YmdHis') . '.pdf';
    }
}
