using Domain.Entities;
using Domain.Generics;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Models.Helpers;
using Models.Interfaces;
using Models.Models;

namespace Models.Repositories
{
    public class PhSCustomerRepository(PhronCareOperationsHubContext context, ILogger<PhSCustomerRepository> logger) : IPhSCustomerRepository
    {
        #region Declaraciones y Constructor
        private readonly PhronCareOperationsHubContext _context = context;
        #endregion
        #region Métodos de clase
        public async Task<PagedResult<ECustomer>> GetAllAsync(int page = 1, int pageSize = 50)
        {
            var query = _context.PhSCustomers
                .Include(c => c.Accounttypes)
                .Include(c => c.PhSCustomerAddresses)
                .Include(c => c.PhSCustomerDocuments)
                .AsQueryable();

            var pagedEntities = await query.ToPagedResultAsync(page, pageSize);

            return new PagedResult<ECustomer>
            {
                Items = pagedEntities.Items.Select(EntityMapper.MapEntity<PhSCustomer, ECustomer>),
                TotalItems = pagedEntities.TotalItems,
                Page = pagedEntities.Page,
                PageSize = pagedEntities.PageSize
            };
        }
        public async Task<ECustomer?> GetByIdAsync(int id)
        {
            var customer = await _context.PhSCustomers
                .Include(c => c.Accounttypes)
                .Include(c => c.PhSCustomerAddresses)
                .Include(c => c.PhSCustomerDocuments)
                .FirstOrDefaultAsync(c => c.Id == id);

            return customer != null ? EntityMapper.MapEntity<PhSCustomer, ECustomer>(customer) : null;
        }
        public async Task<PagedResult<ECustomer>> SearchAsync(
            string? name, string? email, string? document,
            int page = 1, int pageSize = 50)
        {
            var query = _context.PhSCustomers
                .Include(c => c.Accounttypes)
                .Include(c => c.PhSCustomerDocuments)
                .Include(c => c.PhSCustomerAddresses)
                .AsQueryable();

            if (!string.IsNullOrWhiteSpace(name))
            {
                var lowered = name.ToLower();
                query = query.Where(c =>
                    c.Name.ToLower().Contains(lowered) ||
                    c.BusinessName.ToLower().Contains(lowered));
            }

            if (!string.IsNullOrWhiteSpace(document) && document != "?")
            {
                query = query.Where(c =>
                    c.PhSCustomerDocuments.Any(d =>
                        EF.Functions.Like(d.DocumentNumber, $"%{document}%")));
            }

            if (!string.IsNullOrWhiteSpace(email))
            {
                var lowered = email.ToLower();
                query = query.Where(c =>
                    c.PhSCustomerAddresses.Any(a =>
                        a.Email.ToLower().Contains(lowered)));
            }

            var pagedEntities = await query.ToPagedResultAsync(page, pageSize);

            return new PagedResult<ECustomer>
            {
                Items = pagedEntities.Items.Select(EntityMapper.MapEntity<PhSCustomer, ECustomer>),
                TotalItems = pagedEntities.TotalItems,
                Page = pagedEntities.Page,
                PageSize = pagedEntities.PageSize
            };
        }
        public async Task<ECustomer> CreateAsync(ECustomer entity)
        {
            if (entity == null)
            {
                throw new ArgumentNullException(nameof(entity), "El cliente no puede ser nulo.");
            }
            try
            {
                var customer = EntityMapper.MapEntity<ECustomer, PhSCustomer>(entity);
                // Mapeo de direcciones
                foreach (var address in entity.PhSCustomerAddresses)
                {
                    var mappedAddress = EntityMapper.MapEntity<ECustomerAddress, PhSCustomerAddress>(address);
                    customer.PhSCustomerAddresses.Add(mappedAddress);
                }
                // Mapeo de documentos
                foreach (var doc in entity.PhSCustomerDocuments)
                {
                    var mappedDoc = EntityMapper.MapEntity<ECustomerDocument, PhSCustomerDocument>(doc);
                    customer.PhSCustomerDocuments.Add(mappedDoc);
                }
                // Agregar el cliente al contexto de la base de datos
                await _context.PhSCustomers.AddAsync(customer);
                await _context.SaveChangesAsync();
                // Mapear y devolver el cliente con la estructura de dominio
                return EntityMapper.MapEntity<PhSCustomer, ECustomer>(customer);
            }
            catch (DbUpdateException dbEx)
            {
                // Error relacionado con la base de datos (como violación de integridad referencial)
                throw new Exception("Error al guardar el cliente en la base de datos. Es posible que haya un problema con la integridad de los datos.", dbEx);
            }
            catch (Exception ex)
            {
                // Captura cualquier otro tipo de excepción
                throw new Exception("Error inesperado al crear el cliente: " + ex.Message, ex);
            }
        }
        public async Task<bool> UpdateAsync(ECustomer entity)
        {
            if (entity == null)
                throw new ArgumentNullException(nameof(entity));

            try
            {
                var existingCustomer = await _context.PhSCustomers
                    .Include(c => c.PhSCustomerAddresses)
                    .Include(c => c.PhSCustomerDocuments)
                    .FirstOrDefaultAsync(c => c.Id == entity.Id);

                if (existingCustomer == null)
                    return false;

                EntityMapper.MapEntityToExisting(entity, existingCustomer);

                _context.PhSCustomerAddresses.RemoveRange(existingCustomer.PhSCustomerAddresses);
                existingCustomer.PhSCustomerAddresses.Clear();

                foreach (var address in entity.PhSCustomerAddresses)
                {
                    var mappedAddress = EntityMapper.MapEntity<ECustomerAddress, PhSCustomerAddress>(address);
                    existingCustomer.PhSCustomerAddresses.Add(mappedAddress);
                }

                _context.PhSCustomerDocuments.RemoveRange(existingCustomer.PhSCustomerDocuments);
                existingCustomer.PhSCustomerDocuments.Clear();

                foreach (var doc in entity.PhSCustomerDocuments)
                {
                    var mappedDoc = EntityMapper.MapEntity<ECustomerDocument, PhSCustomerDocument>(doc);
                    existingCustomer.PhSCustomerDocuments.Add(mappedDoc);
                }

                await _context.SaveChangesAsync();
                return true;
            }
            catch (Exception ex)
            {
                // Podés loguear el error si querés
                return false;
            }
        }
        public async Task<bool> DeleteAsync(int id)
        {
            var customer = await _context.PhSCustomers.FindAsync(id);
            if (customer == null) return false;

            _context.PhSCustomers.Remove(customer);
            await _context.SaveChangesAsync();
            return true;
        }
        #endregion
    }
}