using Microsoft.EntityFrameworkCore;
using Core.Dtos;
using Domain.Entities;
using Domain.Generics;
using Models.Interfaces;
using Models.Helpers;
using Models.Models;

namespace Models.Repositories
{
    public class PhSQuoteRepository(PhronCareOperationsHubContext context,
                    IPhSFormSeriesRepository formSeriesRepository) : IQuoteRepository
    {
        private readonly PhronCareOperationsHubContext _context = context;
        private readonly IPhSFormSeriesRepository _formSeriesRepository = formSeriesRepository;
        #region Busqueda usando el QuoteDto
        public async Task<PagedResult<QuoteDto>> SearchAsync(
            int? customerId,
            string? customerText,
            string? quoteNumber,
            int? professionalId,
            string? professionalText,
            int? institutionId,
            string? institutionText,
            int? patientId,
            string? patientText,
            DateTime? issueDateFrom,
            DateTime? issueDateTo,
            string? status,
            int page = 1,
            int pageSize = 50)
        {
            // 1) Base query with includes
            var query = _context.PhSQuoteHeaders
                .Include(q => q.PhSQuoteDetails)
                .Include(q => q.PhSQuoteRoles)
                .Include(q => q.PhSQuoteAdjustments)
                .Include(q => q.PhSQuoteTaxes)
                .AsQueryable();

            // 2) Apply filters
            if (customerId.HasValue)
                query = query.Where(q => q.CustomerId == customerId.Value);
            else if (!string.IsNullOrWhiteSpace(customerText))
                query = query.Where(q =>
                    _context.PhSCustomers.Any(c =>
                        c.Id == q.CustomerId &&
                        c.Name.Contains(customerText)));

            if (!string.IsNullOrWhiteSpace(quoteNumber))
                query = query.Where(q => q.Quotenumber.Contains(quoteNumber));

            if (professionalId.HasValue)
            {
                query = query.Where(q =>
                    q.PhSQuoteRoles.Any(r =>
                        r.Entitytype == PhSEntityTypes.Professional &&
                        r.EntityId == professionalId.Value));
            }
            else if (!string.IsNullOrWhiteSpace(professionalText))
            {
                query = query.Where(q =>
                    q.PhSQuoteRoles.Any(r =>
                        r.Entitytype == PhSEntityTypes.Professional &&
                        _context.PhSProfessionals.Any(p =>
                            p.Id == r.EntityId &&
                            p.Fullname.Contains(professionalText))));
            }

            if (institutionId.HasValue)
            {
                query = query.Where(q =>
                    q.PhSQuoteRoles.Any(r =>
                        r.Entitytype == PhSEntityTypes.Institution &&
                        r.EntityId == institutionId.Value));
            }
            else if (!string.IsNullOrWhiteSpace(institutionText))
            {
                query = query.Where(q =>
                    q.PhSQuoteRoles.Any(r =>
                        r.Entitytype == PhSEntityTypes.Institution &&
                        _context.PhSInstitutions.Any(i =>
                            i.Id == r.EntityId &&
                            i.Name.Contains(institutionText))));
            }

            if (patientId.HasValue)
            {
                query = query.Where(q =>
                    q.PhSQuoteRoles.Any(r =>
                        r.Entitytype == PhSEntityTypes.Patient &&
                        r.EntityId == patientId.Value));
            }
            else if (!string.IsNullOrWhiteSpace(patientText))
            {
                query = query.Where(q =>
                    q.PhSQuoteRoles.Any(r =>
                        r.Entitytype == PhSEntityTypes.Patient &&
                        (_context.PhSPatients.Any(pt =>
                             pt.Id == r.EntityId &&
                             pt.Firstname.Contains(patientText)) ||
                         _context.PhSPatients.Any(pt =>
                             pt.Id == r.EntityId &&
                             pt.Lastname.Contains(patientText)))));
            }

            if (issueDateFrom.HasValue)
                query = query.Where(q => q.Issuedate >= issueDateFrom.Value);
            if (issueDateTo.HasValue)
                query = query.Where(q => q.Issuedate <= issueDateTo.Value);

            if (!string.IsNullOrWhiteSpace(status))
                query = query.Where(q => q.Status == status);

            // 3) Execute paged query
            var pagedEntities = await query.ToPagedResultAsync(page, pageSize);

            // 4) Project to DTOs
            var dtos = pagedEntities.Items.Select(header =>
            {
                // Precompute tax sums
                var totalTaxAmount = header.PhSQuoteTaxes.Sum(t => t.Taxamount);
                var netBase = header.Netamount.GetValueOrDefault() != 0m
                              ? header.Netamount.Value
                              : 1m;

                return new QuoteDto
                {
                    Id = header.Id,
                    Quotenumber = header.Quotenumber,
                    IssueDate = header.Issuedate,
                    EstimatedDate = header.Estimateddate,
                    CustomerName = _context.PhSCustomers
                                            .Where(c => c.Id == header.CustomerId)
                                            .Select(c => c.Name)
                                            .FirstOrDefault() ?? "",
                    ProfessionalName = header.PhSQuoteRoles
                                            .Where(r => r.Entitytype == PhSEntityTypes.Professional)
                                            .Select(r => _context.PhSProfessionals
                                                               .Where(p => p.Id == r.EntityId)
                                                               .Select(p => p.Fullname)
                                                               .FirstOrDefault())
                                            .FirstOrDefault() ?? "",
                    InstitutionName = header.PhSQuoteRoles
                                            .Where(r => r.Entitytype == PhSEntityTypes.Institution)
                                            .Select(r => _context.PhSInstitutions
                                                               .Where(i => i.Id == r.EntityId)
                                                               .Select(i => i.Name)
                                                               .FirstOrDefault())
                                            .FirstOrDefault() ?? "",
                    PatientName = header.PhSQuoteRoles
                                            .Where(r => r.Entitytype == PhSEntityTypes.Patient)
                                            .Select(r => _context.PhSPatients
                                                               .Where(pt => pt.Id == r.EntityId)
                                                               .Select(pt => (pt.Firstname + " " + pt.Lastname).Trim())
                                                               .FirstOrDefault())
                                            .FirstOrDefault() ?? "",
                    BusinessUnitName = _context.PhSBusinessUnits
                                            .Where(b => b.Id == header.BusinessunitId)
                                            .Select(b => b.Code)
                                            .FirstOrDefault() ?? "",
                    Currency = header.Currency,
                    Total = header.Total.GetValueOrDefault(0m),
                    Status = header.Status.Trim(),
                    SalespersonName = _context.PhSPeople
                                            .Where(u => u.Id == header.PeopleId)
                                            .Select(u => u.Name)
                                            .FirstOrDefault() ?? "",

                    Items = header.PhSQuoteDetails.Select(d =>
                    {
                        var itemBase = d.Quantity * d.Unitprice;
                        var itemTax = totalTaxAmount * itemBase / netBase;
                        return new QuoteItemDto
                        {
                            Description = d.ProductDescription,
                            Quantity = d.Quantity,
                            UnitPrice = d.Unitprice,
                            Subtotal = itemBase,
                            TaxAmount = itemTax,
                            Total = itemBase + itemTax
                        };
                    }).ToList(),

                    Taxes = header.PhSQuoteTaxes.Select(t => new QuoteTaxDto
                    {
                        TaxName = t.Taxname,
                        TaxCode = t.Taxcode,
                        TaxableAmount = t.TaxableAmount,
                        TaxRate = t.Taxrate,
                        TaxAmount = t.Taxamount,
                        IsIncludedInPrice = t.IsIncludedInPrice
                    }).ToList(),

                    Adjustments = header.PhSQuoteAdjustments.Select(a => new QuoteAdjustmentDto
                    {
                        Reason = _context.PhSAdjustmentReasons
                                    .Where(r => r.Code == a.ReasonCode)
                                    .Select(r => r.Description)
                                    .FirstOrDefault() ?? "",
                        Amount = a.Amount.GetValueOrDefault(0m)
                    }).ToList()
                };
            }).ToList();

            // 5) Return paged DTO result
            return new PagedResult<QuoteDto>
            {
                Items = dtos,
                TotalItems = pagedEntities.TotalItems,
                Page = pagedEntities.Page,
                PageSize = pagedEntities.PageSize
            };
        }

        #endregion
        #region Guardado completo de presupuesto (encabezado + detalles + roles + ajustes + impuestos)
        /// <summary>
        /// Crea un nuevo presupuesto, incluyendo encabezado, detalles, roles, ajustes e impuestos asociados.
        /// Genera automáticamente el número de presupuesto en base a la serie indicada.
        /// <param name="quote">Presupuesto a registrar, incluyendo entidades relacionadas.</param>
        /// <param name="formSeriesId">Identificador de la serie de numeración a utilizar.</param>
        /// <returns>Cadena con el número generado del presupuesto.</returns>
        /// </summary>
        public async Task<string> CreateFullQuoteAsync(EQuoteHeader quote, int formSeriesId)
        {
            using var transaction = await _context.Database.BeginTransactionAsync();
            try
            {
                var nextNumber = await _formSeriesRepository.GetNextInternalNumberAsync(formSeriesId);
                var series = await _formSeriesRepository.GetByIdAsync(formSeriesId)
                                   ?? throw new InvalidOperationException("Serie no encontrada");
                int padding = 8; /* format "00000000" */
                quote.Status = "Emitido";
                quote.Quotenumber = $"{series.Letter}-{nextNumber.ToString($"D{padding}")}";

                var headerEntity = EntityMapper.MapEntity<EQuoteHeader, PhSQuoteHeader>(quote);
                _context.PhSQuoteHeaders.Add(headerEntity);

                #region Nota: Esta seccion queda para futura modificacion en caso de cambiar CASCADE INSERT de las entidades relacionadas
                //// Guardado de Detalles
                //if (quote.PhSQuoteDetails?.Any() == true)
                //{
                //    foreach (var detail in quote.PhSQuoteDetails)
                //    {
                //        detail.QuoteheaderId = headerEntity.Id;
                //        var dbDetail = EntityMapper.MapEntity<EQuoteDetail, PhSQuoteDetail>(detail);
                //        _context.PhSQuoteDetails.Add(dbDetail);
                //    }
                //}

                //// Guardado de Roles
                //if (quote.PhSQuoteRoles?.Any() == true)
                //{
                //    foreach (var role in quote.PhSQuoteRoles)
                //    {
                //        role.QuoteheaderId = headerEntity.Id;
                //        var dbRole = EntityMapper.MapEntity<EQuoteRole, PhSQuoteRole>(role);
                //        _context.PhSQuoteRoles.Add(dbRole);
                //    }
                //}

                //// Guardado de Ajustes
                //if (quote.PhSQuoteAdjustments?.Any() == true)
                //{
                //    foreach (var adj in quote.PhSQuoteAdjustments)
                //    {
                //        adj.QuoteheaderId = headerEntity.Id;
                //        var dbAdj = EntityMapper.MapEntity<EQuoteAdjustment, PhSQuoteAdjustment>(adj);
                //        _context.PhSQuoteAdjustments.Add(dbAdj);
                //    }
                //}

                //// Guardado de Impuestos
                //if (quote.PhSQuoteTaxes?.Any() == true)
                //{
                //    foreach (var tax in quote.PhSQuoteTaxes)
                //    {
                //        tax.QuoteheaderId = headerEntity.Id;
                //        var dbTax = EntityMapper.MapEntity<EQuoteTax, PhSQuoteTaxis>(tax);
                //        _context.PhSQuoteTaxes.Add(dbTax);
                //    }
                //}
                #endregion

                await _context.SaveChangesAsync();
                await transaction.CommitAsync();
                return headerEntity.Quotenumber;
           }
            catch
            {
                await transaction.RollbackAsync();
                throw;
            }
        }
        #endregion
    }
}