using GestionIntegral.Api.Data.Repositories; // Para IZonaRepository
using GestionIntegral.Api.Data.Repositories.Distribucion;
using GestionIntegral.Api.Dtos.Auditoria;
using GestionIntegral.Api.Dtos.Zonas;
using GestionIntegral.Api.Models.Distribucion; // Para Zona
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace GestionIntegral.Api.Services.Distribucion
{
    public class ZonaService : IZonaService
    {
        private readonly IZonaRepository _zonaRepository;
        private readonly ILogger<ZonaService> _logger;

        public ZonaService(IZonaRepository zonaRepository, ILogger<ZonaService> logger)
        {
            _zonaRepository = zonaRepository;
            _logger = logger;
        }

        public async Task<IEnumerable<ZonaDto>> ObtenerTodasAsync(string? nombreFilter, string? descripcionFilter)
        {
            var zonas = await _zonaRepository.GetAllAsync(nombreFilter, descripcionFilter, soloActivas: true); // Solo activas por defecto
            // Mapeo Entidad -> DTO
            return zonas.Select(z => new ZonaDto
            {
                IdZona = z.IdZona,
                Nombre = z.Nombre,
                Descripcion = z.Descripcion
            });
        }

        public async Task<ZonaDto?> ObtenerPorIdAsync(int id)
        {
            var zona = await _zonaRepository.GetByIdAsync(id, soloActivas: true); // Solo activa por defecto
            if (zona == null) return null;

            // Mapeo Entidad -> DTO
            return new ZonaDto
            {
                IdZona = zona.IdZona,
                Nombre = zona.Nombre,
                Descripcion = zona.Descripcion
            };
        }

        public async Task<(ZonaDto? Zona, string? Error)> CrearAsync(CreateZonaDto createDto, int idUsuario)
        {
            // Validación: Nombre duplicado (entre zonas activas)
            if (await _zonaRepository.ExistsByNameAsync(createDto.Nombre, null, soloActivas: true))
            {
                return (null, "El nombre de la zona ya existe.");
            }

            var nuevaZona = new Zona
            {
                Nombre = createDto.Nombre,
                Descripcion = createDto.Descripcion,
                Estado = true // Las zonas nuevas siempre están activas
            };

            var zonaCreada = await _zonaRepository.CreateAsync(nuevaZona, idUsuario);

            if (zonaCreada == null)
            {
                _logger.LogError("Falló la creación de la Zona en el repositorio para el nombre: {Nombre}", createDto.Nombre);
                return (null, "Error al crear la zona en la base de datos.");
            }

            // Mapeo de Entidad creada a DTO
            var zonaDto = new ZonaDto
            {
                IdZona = zonaCreada.IdZona,
                Nombre = zonaCreada.Nombre,
                Descripcion = zonaCreada.Descripcion
            };

            return (zonaDto, null); // Éxito
        }

        public async Task<(bool Exito, string? Error)> ActualizarAsync(int id, UpdateZonaDto updateDto, int idUsuario)
        {
            // Verificar si la zona existe y está activa para poder modificarla (regla de negocio)
            var zonaExistente = await _zonaRepository.GetByIdAsync(id, soloActivas: true);
            if (zonaExistente == null)
            {
                // Podría no existir o estar inactiva
                var zonaInactiva = await _zonaRepository.GetByIdAsync(id, soloActivas: false);
                if (zonaInactiva != null)
                    return (false, "No se puede modificar una zona eliminada (inactiva).");
                else
                    return (false, "Zona no encontrada.");
            }

            // Validación: Nombre duplicado (excluyendo el ID actual, entre zonas activas)
            if (await _zonaRepository.ExistsByNameAsync(updateDto.Nombre, id, soloActivas: true))
            {
                return (false, "El nombre de la zona ya existe para otro registro activo.");
            }

            // Mapeo de DTO a Entidad para actualizar
            zonaExistente.Nombre = updateDto.Nombre;
            zonaExistente.Descripcion = updateDto.Descripcion;
            // No modificamos el estado aquí, solo nombre y descripción

            var actualizado = await _zonaRepository.UpdateAsync(zonaExistente, idUsuario);

            if (!actualizado)
            {
                _logger.LogError("Falló la actualización de la Zona en el repositorio para el ID: {Id}", id);
                return (false, "Error al actualizar la zona en la base de datos.");
            }
            return (true, null); // Éxito
        }

        public async Task<(bool Exito, string? Error)> EliminarAsync(int id, int idUsuario)
        {
            // Verificar si la zona existe (incluso si está inactiva, para evitar errores)
            var zonaExistente = await _zonaRepository.GetByIdAsync(id, soloActivas: false);
            if (zonaExistente == null)
            {
                return (false, "Zona no encontrada.");
            }
            // Si ya está inactiva, consideramos la operación exitosa (idempotencia)
            if (!zonaExistente.Estado)
            {
                return (true, null);
            }

            // Validación: No se puede eliminar si está en uso por distribuidores o canillas activos
            if (await _zonaRepository.IsInUseAsync(id))
            {
                return (false, "No se puede eliminar. La zona está asignada a distribuidores o canillas activos.");
            }

            // Realizar el Soft Delete
            var eliminado = await _zonaRepository.SoftDeleteAsync(id, idUsuario);
            if (!eliminado)
            {
                _logger.LogError("Falló la eliminación lógica de la Zona en el repositorio para el ID: {Id}", id);
                return (false, "Error al eliminar la zona de la base de datos.");
            }
            return (true, null); // Éxito
        }
        
        public async Task<IEnumerable<ZonaHistorialDto>> ObtenerHistorialAsync(
        DateTime? fechaDesde, DateTime? fechaHasta,
        int? idUsuarioModifico, string? tipoModificacion,
        int? idZonaAfectada)
    {
        var historialData = await _zonaRepository.GetHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idZonaAfectada);
        
        return historialData.Select(h => new ZonaHistorialDto
        {
            Id_Zona = h.Historial.Id_Zona,
            Nombre = h.Historial.Nombre,
            Descripcion = h.Historial.Descripcion,
            Estado = h.Historial.Estado,
            Id_Usuario = h.Historial.Id_Usuario,
            NombreUsuarioModifico = h.NombreUsuarioModifico,
            FechaMod = h.Historial.FechaMod,
            TipoMod = h.Historial.TipoMod
        }).ToList();
    }
    }
}