using Dapper;
using GestionIntegral.Api.Models.Distribucion;
using System.Collections.Generic;
using System.Data;
using System.Text; // Para StringBuilder
using System.Threading.Tasks;

namespace GestionIntegral.Api.Data.Repositories.Distribucion
{
    public class ZonaRepository : IZonaRepository
    {
        private readonly DbConnectionFactory _connectionFactory;
        private readonly ILogger<ZonaRepository> _logger;

        public ZonaRepository(DbConnectionFactory connectionFactory, ILogger<ZonaRepository> logger)
        {
            _connectionFactory = connectionFactory;
            _logger = logger;
        }

        public async Task<IEnumerable<Zona>> GetAllAsync(string? nombreFilter, string? descripcionFilter, bool soloActivas = true)
        {
            var sqlBuilder = new StringBuilder("SELECT Id_Zona AS IdZona, Nombre, Descripcion, Estado FROM dbo.dist_dtZonas WHERE 1=1");
            var parameters = new DynamicParameters();

            if (soloActivas)
            {
                sqlBuilder.Append(" AND Estado = 1");
            }
            if (!string.IsNullOrWhiteSpace(nombreFilter))
            {
                sqlBuilder.Append(" AND Nombre LIKE @NombreFilter");
                parameters.Add("NombreFilter", $"%{nombreFilter}%");
            }
            if (!string.IsNullOrWhiteSpace(descripcionFilter))
            {
                sqlBuilder.Append(" AND Descripcion LIKE @DescripcionFilter");
                parameters.Add("DescripcionFilter", $"%{descripcionFilter}%");
            }
            sqlBuilder.Append(" ORDER BY Nombre;");

            try
            {
                using (var connection = _connectionFactory.CreateConnection())
                {
                    return await connection.QueryAsync<Zona>(sqlBuilder.ToString(), parameters);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error al obtener todas las Zonas. Filtros: Nombre={NombreFilter}, Descripcion={DescFilter}", nombreFilter, descripcionFilter);
                return Enumerable.Empty<Zona>();
            }
        }

        public async Task<Zona?> GetByIdAsync(int id, bool soloActivas = true)
        {
            var sqlBuilder = new StringBuilder("SELECT Id_Zona AS IdZona, Nombre, Descripcion, Estado FROM dbo.dist_dtZonas WHERE Id_Zona = @Id");
            if (soloActivas)
            {
                sqlBuilder.Append(" AND Estado = 1");
            }
            try
            {
                using (var connection = _connectionFactory.CreateConnection())
                {
                    return await connection.QuerySingleOrDefaultAsync<Zona>(sqlBuilder.ToString(), new { Id = id });
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error al obtener Zona por ID: {IdZona}", id);
                return null;
            }
        }

        public async Task<bool> ExistsByNameAsync(string nombre, int? excludeId = null, bool soloActivas = true)
        {
            var sqlBuilder = new StringBuilder("SELECT COUNT(1) FROM dbo.dist_dtZonas WHERE Nombre = @Nombre");
            var parameters = new DynamicParameters();
            parameters.Add("Nombre", nombre);

            if (soloActivas)
            {
                sqlBuilder.Append(" AND Estado = 1");
            }
            if (excludeId.HasValue)
            {
                sqlBuilder.Append(" AND Id_Zona != @ExcludeId");
                parameters.Add("ExcludeId", excludeId.Value);
            }

            try
            {
                using (var connection = _connectionFactory.CreateConnection())
                {
                    var count = await connection.ExecuteScalarAsync<int>(sqlBuilder.ToString(), parameters);
                    return count > 0;
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error en ExistsByNameAsync para Zona con nombre: {Nombre}", nombre);
                return true;
            }
        }

        public async Task<Zona?> CreateAsync(Zona nuevaZona, int idUsuario)
        {
            // Las nuevas zonas siempre se crean con Estado = 1
            var sqlInsert = @"
                INSERT INTO dbo.dist_dtZonas (Nombre, Descripcion, Estado)
                OUTPUT INSERTED.Id_Zona AS IdZona, INSERTED.Nombre, INSERTED.Descripcion, INSERTED.Estado
                VALUES (@Nombre, @Descripcion, 1);";

            var sqlInsertHistorico = @"
                INSERT INTO dbo.dist_dtZonas_H (Id_Zona, Nombre, Descripcion, Estado, Id_Usuario, FechaMod, TipoMod)
                VALUES (@IdZona, @Nombre, @Descripcion, @Estado, @IdUsuario, @FechaMod, @TipoMod);";
            try
            {
                using (var connection = _connectionFactory.CreateConnection())
                {
                    connection.Open();
                    using (var transaction = connection.BeginTransaction())
                    {
                        try
                        {
                            var insertedZona = await connection.QuerySingleAsync<Zona>(
                                sqlInsert,
                                new { nuevaZona.Nombre, nuevaZona.Descripcion },
                                transaction: transaction
                            );

                            await connection.ExecuteAsync(sqlInsertHistorico, new
                            {
                                IdZona = insertedZona.IdZona,
                                insertedZona.Nombre,
                                insertedZona.Descripcion,
                                Estado = insertedZona.Estado, // Será true (1)
                                IdUsuario = idUsuario,
                                FechaMod = DateTime.Now,
                                TipoMod = "Insertada"
                            }, transaction: transaction);

                            transaction.Commit();
                            return insertedZona;
                        }
                        catch (Exception exTrans)
                        {
                            transaction.Rollback();
                            _logger.LogError(exTrans, "Error en transacción CreateAsync para Zona. Nombre: {Nombre}", nuevaZona.Nombre);
                            return null;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error general en CreateAsync para Zona. Nombre: {Nombre}", nuevaZona.Nombre);
                return null;
            }
        }

        public async Task<bool> UpdateAsync(Zona zonaAActualizar, int idUsuario)
        {
            var zonaActual = await GetByIdAsync(zonaAActualizar.IdZona, soloActivas: false); // Obtener incluso si está inactiva para el historial
            if (zonaActual == null) return false;

            // Solo actualizamos si está activa, pero el historial registra el estado que tenía.
            // El servicio decidirá si se puede actualizar una zona inactiva.
            var sqlUpdate = @"
                UPDATE dbo.dist_dtZonas
                SET Nombre = @Nombre, Descripcion = @Descripcion
                WHERE Id_Zona = @IdZona;"; //  Podríamos añadir AND Estado = 1 si el servicio lo requiere así estrictamente.

            var sqlInsertHistorico = @"
                INSERT INTO dbo.dist_dtZonas_H (Id_Zona, Nombre, Descripcion, Estado, Id_Usuario, FechaMod, TipoMod)
                VALUES (@IdZona, @NombreActual, @DescripcionActual, @EstadoActual, @IdUsuario, @FechaMod, @TipoMod);";
            try
            {
                using (var connection = _connectionFactory.CreateConnection())
                {
                    connection.Open();
                    using (var transaction = connection.BeginTransaction())
                    {
                        try
                        {
                            // Registrar el estado *antes* de la modificación
                            await connection.ExecuteAsync(sqlInsertHistorico, new
                            {
                                IdZona = zonaActual.IdZona,
                                NombreActual = zonaActual.Nombre,
                                DescripcionActual = zonaActual.Descripcion,
                                EstadoActual = zonaActual.Estado,
                                IdUsuario = idUsuario,
                                FechaMod = DateTime.Now,
                                TipoMod = "Modificada"
                            }, transaction: transaction);

                            var rowsAffected = await connection.ExecuteAsync(sqlUpdate, new
                            {
                                zonaAActualizar.Nombre,
                                zonaAActualizar.Descripcion,
                                zonaAActualizar.IdZona
                            }, transaction: transaction);

                            transaction.Commit();
                            return rowsAffected == 1;
                        }
                        catch (Exception exTrans)
                        {
                            transaction.Rollback();
                            _logger.LogError(exTrans, "Error en transacción UpdateAsync para Zona ID: {IdZona}", zonaAActualizar.IdZona);
                            return false;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error general en UpdateAsync para Zona ID: {IdZona}", zonaAActualizar.IdZona);
                return false;
            }
        }

        public async Task<bool> SoftDeleteAsync(int id, int idUsuario)
        {
            var zonaActual = await GetByIdAsync(id, soloActivas: false); // Obtenerla sin importar su estado para el historial
            if (zonaActual == null) return false;
            if (!zonaActual.Estado) return true; // Ya está "eliminada" (inactiva), considerar éxito

            var sqlSoftDelete = @"UPDATE dbo.dist_dtZonas SET Estado = 0 WHERE Id_Zona = @IdZona;";
            var sqlInsertHistorico = @"
                INSERT INTO dbo.dist_dtZonas_H (Id_Zona, Nombre, Descripcion, Estado, Id_Usuario, FechaMod, TipoMod)
                VALUES (@IdZona, @Nombre, @Descripcion, @EstadoNuevo, @IdUsuario, @FechaMod, @TipoMod);";
            try
            {
                using (var connection = _connectionFactory.CreateConnection())
                {
                    connection.Open();
                    using (var transaction = connection.BeginTransaction())
                    {
                        try
                        {
                            // Actualizar la tabla principal
                            var rowsAffected = await connection.ExecuteAsync(sqlSoftDelete, new { IdZona = id }, transaction: transaction);

                            if (rowsAffected == 1)
                            {
                                // Registrar en el historial con el nuevo estado (0)
                                await connection.ExecuteAsync(sqlInsertHistorico, new
                                {
                                    IdZona = zonaActual.IdZona,
                                    zonaActual.Nombre,
                                    zonaActual.Descripcion,
                                    EstadoNuevo = false, // El estado después del soft delete
                                    IdUsuario = idUsuario,
                                    FechaMod = DateTime.Now,
                                    TipoMod = "Eliminada" // O "Deshabilitada"
                                }, transaction: transaction);
                            }

                            transaction.Commit();
                            return rowsAffected == 1;
                        }
                        catch (Exception exTrans)
                        {
                            transaction.Rollback();
                            _logger.LogError(exTrans, "Error en transacción SoftDeleteAsync para Zona ID: {IdZona}", id);
                            return false;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error general en SoftDeleteAsync para Zona ID: {IdZona}", id);
                return false;
            }
        }

        public async Task<bool> IsInUseAsync(int id)
        {
            // Verifica en dist_dtDistribuidores y dist_dtCanillas
            var sqlCheckDist = "SELECT COUNT(1) FROM dbo.dist_dtDistribuidores WHERE Id_Zona = @IdZona";
            var sqlCheckCanillas = "SELECT COUNT(1) FROM dbo.dist_dtCanillas WHERE Id_Zona = @IdZona AND Baja = 0"; // Solo canillas activos
            try
            {
                using (var connection = _connectionFactory.CreateConnection())
                {
                    var countDist = await connection.ExecuteScalarAsync<int>(sqlCheckDist, new { IdZona = id });
                    if (countDist > 0) return true;

                    var countCanillas = await connection.ExecuteScalarAsync<int>(sqlCheckCanillas, new { IdZona = id });
                    return countCanillas > 0;
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error en IsInUseAsync para Zona ID: {IdZona}", id);
                return true; // Asumir que está en uso si hay error
            }
        }
        public async Task<IEnumerable<(ZonaHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
        DateTime? fechaDesde, DateTime? fechaHasta,
        int? idUsuarioModifico, string? tipoModificacion,
        int? idZonaOriginal)
        {
            using var connection = _connectionFactory.CreateConnection();
            var sqlBuilder = new StringBuilder(@"
            SELECT 
                h.Id_Zona, h.Nombre, h.Descripcion, h.Estado,
                h.Id_Usuario, h.FechaMod, h.TipoMod,
                u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico
            FROM dbo.dist_dtZonas_H h
            JOIN dbo.gral_Usuarios u ON h.Id_Usuario = u.Id
            WHERE 1=1");

            var parameters = new DynamicParameters();

            if (fechaDesde.HasValue) { sqlBuilder.Append(" AND h.FechaMod >= @FechaDesdeParam"); parameters.Add("FechaDesdeParam", fechaDesde.Value.Date); }
            if (fechaHasta.HasValue) { sqlBuilder.Append(" AND h.FechaMod <= @FechaHastaParam"); parameters.Add("FechaHastaParam", fechaHasta.Value.Date.AddDays(1).AddTicks(-1)); }
            if (idUsuarioModifico.HasValue) { sqlBuilder.Append(" AND h.Id_Usuario = @IdUsuarioModificoParam"); parameters.Add("IdUsuarioModificoParam", idUsuarioModifico.Value); }
            if (!string.IsNullOrWhiteSpace(tipoModificacion)) { sqlBuilder.Append(" AND h.TipoMod = @TipoModParam"); parameters.Add("TipoModParam", tipoModificacion); }
            if (idZonaOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Zona = @IdZonaOriginalParam"); parameters.Add("IdZonaOriginalParam", idZonaOriginal.Value); }

            sqlBuilder.Append(" ORDER BY h.FechaMod DESC;");

            try
            {
                var result = await connection.QueryAsync<ZonaHistorico, string, (ZonaHistorico, string)>(
                    sqlBuilder.ToString(),
                    (hist, userName) => (hist, userName),
                    parameters,
                    splitOn: "NombreUsuarioModifico"
                );
                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error al obtener historial de Zonas (Maestro).");
                return Enumerable.Empty<(ZonaHistorico, string)>();
            }
        }
    }
}