using foundation_system.Data;
using foundation_system.Models;
using foundation_system.Models.ViewModels;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;

namespace foundation_system.Controllers
{
    [Authorize]
    public class MovimientoCajaController : Controller
    {
        private readonly ApplicationDbContext _context;

        public MovimientoCajaController(ApplicationDbContext context)
        {
            _context = context;
        }

        // GET: MovimientoCaja/CreateGasto?cajaId=5
        public async Task<IActionResult> CreateGasto(int cajaId)
        {
            var caja = await _context.CajasChicas.FindAsync(cajaId);
            if (caja == null || caja.Estado != "ABIERTA")
            {
                return NotFound("La caja no existe o está cerrada.");
            }

            var model = new RegistroGastoViewModel
            {
                CajaChicaId = caja.Id,
                CajaChicaNombre = caja.Nombre,
                SaldoDisponible = caja.SaldoActual,
                Fecha = DateOnly.FromDateTime(DateTime.Today)
            };

            ViewData["CategoriaId"] = new SelectList(_context.CategoriasGastos.Where(c => c.Activo), "Id", "Nombre");
            ViewData["ProveedorId"] = new SelectList(_context.Proveedores.Where(p => p.Activo), "Id", "Nombre");
            return View(model);
        }

        // POST: MovimientoCaja/CreateGasto
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> CreateGasto(RegistroGastoViewModel model)
        {
            var caja = await _context.CajasChicas.FindAsync(model.CajaChicaId);
            if (caja == null || caja.Estado != "ABIERTA")
            {
                return NotFound();
            }

            if (model.Monto > caja.SaldoActual)
            {
                ModelState.AddModelError("Monto", "El monto del gasto excede el saldo disponible.");
            }

            if (ModelState.IsValid)
            {
                using var transaction = _context.Database.BeginTransaction();
                try
                {
                    // 1. Create Movement
                    var movimiento = new CajaChicaMovimiento
                    {
                        CajaChicaId = model.CajaChicaId,
                        TipoMovimiento = "GASTO",
                        FechaMovimiento = model.Fecha,
                        Monto = model.Monto,
                        Descripcion = model.Descripcion,
                        CategoriaGastoId = model.CategoriaId,
                        ProveedorId = model.ProveedorId,
                        UsuarioRegistroId = long.Parse(User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value ?? "1"),
                        EstadoReembolso = "PENDIENTE",
                        CreadoEn = DateTime.UtcNow
                    };

                    _context.Add(movimiento);
                    await _context.SaveChangesAsync();

                    // 2. Update Balance
                    caja.SaldoActual -= model.Monto;
                    caja.ActualizadoEn = DateTime.UtcNow;
                    _context.Update(caja);
                    await _context.SaveChangesAsync();

                    await transaction.CommitAsync();
                    return RedirectToAction("Details", "CajaChica", new { id = model.CajaChicaId });
                }
                catch (Exception)
                {
                    await transaction.RollbackAsync();
                    ModelState.AddModelError("", "Ocurrió un error al registrar el gasto.");
                }
            }

            model.CajaChicaNombre = caja.Nombre;
            model.SaldoDisponible = caja.SaldoActual;
            ViewData["CategoriaId"] = new SelectList(_context.CategoriasGastos.Where(c => c.Activo), "Id", "Nombre", model.CategoriaId);
            ViewData["ProveedorId"] = new SelectList(_context.Proveedores.Where(p => p.Activo), "Id", "Nombre", model.ProveedorId);
            return View(model);
        }

        // GET: MovimientoCaja/Reposicion?cajaId=5
        public async Task<IActionResult> Reposicion(int cajaId)
        {
            var caja = await _context.CajasChicas
                .Include(c => c.Movimientos.Where(m => m.TipoMovimiento == "GASTO" && m.EstadoReembolso == "PENDIENTE"))
                .FirstOrDefaultAsync(c => c.Id == cajaId);

            if (caja == null) return NotFound();

            return View(caja);
        }

        // POST: MovimientoCaja/ConfirmarReposicion
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> ConfirmarReposicion(int cajaId, List<long> movimientoIds)
        {
            var caja = await _context.CajasChicas.FindAsync(cajaId);
            if (caja == null) return NotFound();

            if (movimientoIds == null || !movimientoIds.Any())
            {
                return RedirectToAction("Reposicion", new { cajaId });
            }

            using var transaction = _context.Database.BeginTransaction();
            try
            {
                var movimientos = await _context.CajaChicaMovimientos
                    .Where(m => movimientoIds.Contains(m.Id) && m.CajaChicaId == cajaId && m.EstadoReembolso == "PENDIENTE")
                    .ToListAsync();

                decimal totalReembolso = movimientos.Sum(m => m.Monto);

                // 1. Mark expenses as reimbursed
                foreach (var mov in movimientos)
                {
                    mov.EstadoReembolso = "REEMBOLSADO";
                }
                _context.UpdateRange(movimientos);

                // 2. Create Replenishment Movement
                var reposicion = new CajaChicaMovimiento
                {
                    CajaChicaId = cajaId,
                    TipoMovimiento = "REPOSICION",
                    FechaMovimiento = DateOnly.FromDateTime(DateTime.Today),
                    Monto = totalReembolso,
                    Descripcion = $"Reposición de {movimientos.Count} gastos.",
                    UsuarioRegistroId = long.Parse(User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value ?? "1"),
                    CreadoEn = DateTime.UtcNow
                };
                _context.Add(reposicion);

                // 3. Restore Balance
                caja.SaldoActual += totalReembolso;
                caja.ActualizadoEn = DateTime.UtcNow;
                _context.Update(caja);

                await _context.SaveChangesAsync();
                await transaction.CommitAsync();

                return RedirectToAction("Details", "CajaChica", new { id = cajaId });
            }
            catch
            {
                await transaction.RollbackAsync();
                return RedirectToAction("Reposicion", new { cajaId });
            }
        }
        // GET: MovimientoCaja/SearchProveedores
        [HttpGet]
        public async Task<IActionResult> SearchProveedores(string term)
        {
            if (string.IsNullOrWhiteSpace(term) || term.Length < 2)
            {
                return Json(new List<object>());
            }

            var results = await _context.Database
                .SqlQueryRaw<SearchResult>(
                    "SELECT id, text, score FROM buscar_personas_v2(@p0, 'PROVEEDOR')", 
                    term)
                .ToListAsync();

            return Json(results);
        }
    }
}
