using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Haoliang.Models.Production;
using Haoliang.Data;
using Haoliang.Data.Repositories;
using Haoliang.Data.Entities;

namespace Haoliang.Data.Repositories
{
    public interface IProductionRepository : IRepository<ProductionRecordBasic>
    {
        Task<IEnumerable<ProductionRecordBasic>> GetByDeviceAndDateAsync(int deviceId, DateTime date);
        Task<IEnumerable<ProductionRecordBasic>> GetByDeviceAndProgramAsync(int deviceId, string ncProgram);
        Task<IEnumerable<ProductionRecordBasic>> GetByDateRangeAsync(DateTime startDate, DateTime endDate);
        Task<ProductionRecordBasic> GetLatestProductionAsync(int deviceId, string ncProgram);
        Task<int> GetTodayProductionAsync(int deviceId);
        Task<int> GetProductionByDateAsync(int deviceId, DateTime date);
        Task<decimal> GetQualityRateAsync(int deviceId, DateTime date);
        Task<bool> HasProductionDataAsync(int deviceId, DateTime date);
    }

    public class ProductionRepository : Repository<ProductionRecordBasic>, IProductionRepository
    {
        private readonly CNCDbContext _context;

        public ProductionRepository(CNCDbContext context) : base(context)
        {
            _context = context;
        }

        public async Task<IEnumerable<ProductionRecordBasic>> GetByDeviceAndDateAsync(int deviceId, DateTime date)
        {
            return await _context.ProductionRecords
                .Where(pr => pr.DeviceId == deviceId && pr.ProductionDate.Date == date.Date)
                .OrderBy(pr => pr.NCProgram)
                .ThenBy(pr => pr.CreatedAt)
                .ToListAsync();
        }

        public async Task<IEnumerable<ProductionRecordBasic>> GetByDeviceAndProgramAsync(int deviceId, string ncProgram)
        {
            return await _context.ProductionRecords
                .Where(pr => pr.DeviceId == deviceId && pr.NCProgram == ncProgram)
                .OrderByDescending(pr => pr.ProductionDate)
                .ToListAsync();
        }

        public async Task<IEnumerable<ProductionRecordBasic>> GetByDateRangeAsync(DateTime startDate, DateTime endDate)
        {
            return await _context.ProductionRecords
                .Where(pr => pr.ProductionDate >= startDate && pr.ProductionDate <= endDate)
                .OrderBy(pr => pr.ProductionDate)
                .ThenBy(pr => pr.DeviceId)
                .ThenBy(pr => pr.NCProgram)
                .ToListAsync();
        }

        public async Task<ProductionRecordBasic> GetLatestProductionAsync(int deviceId, string ncProgram)
        {
            return await _context.ProductionRecords
                .Where(pr => pr.DeviceId == deviceId && pr.NCProgram == ncProgram)
                .OrderByDescending(pr => pr.ProductionDate)
                .ThenByDescending(pr => pr.CreatedAt)
                .FirstOrDefaultAsync();
        }

        public async Task<int> GetTodayProductionAsync(int deviceId)
        {
            var today = DateTime.Today;
            var productionRecords = await _context.ProductionRecords
                .Where(pr => pr.DeviceId == deviceId && pr.ProductionDate == today)
                .ToListAsync();

            return productionRecords.Sum(pr => pr.Quantity);
        }

        public async Task<int> GetProductionByDateAsync(int deviceId, DateTime date)
        {
            var productionRecords = await _context.ProductionRecords
                .Where(pr => pr.DeviceId == deviceId && pr.ProductionDate.Date == date.Date)
                .ToListAsync();

            return productionRecords.Sum(pr => pr.Quantity);
        }

        public async Task<decimal> GetQualityRateAsync(int deviceId, DateTime date)
        {
            var productionRecords = await _context.ProductionRecords
                .Where(pr => pr.DeviceId == deviceId && pr.ProductionDate.Date == date.Date)
                .ToListAsync();

            if (productionRecords.Any())
            {
                var totalQuantity = productionRecords.Sum(pr => pr.Quantity);
                var totalValidQuantity = productionRecords.Sum(pr => (int)(pr.Quantity * pr.QualityRate / 100));
                return totalQuantity > 0 ? (decimal)totalValidQuantity / totalQuantity * 100 : 100;
            }

            return 100;
        }

        public async Task<bool> HasProductionDataAsync(int deviceId, DateTime date)
        {
            return await _context.ProductionRecords
                .AnyAsync(pr => pr.DeviceId == deviceId && pr.ProductionDate.Date == date.Date);
        }
    }

    public interface IProgramProductionSummaryRepository : IRepository<ProgramProductionSummary>
    {
        Task<ProgramProductionSummary> GetByDeviceProgramDateAsync(int deviceId, string ncProgram, DateTime date);
        Task<IEnumerable<ProgramProductionSummary>> GetByDeviceAndDateAsync(int deviceId, DateTime date);
        Task<IEnumerable<ProgramProductionSummary>> GetByProgramAndDateRangeAsync(string ncProgram, DateTime startDate, DateTime endDate);
        Task<int> GetTotalProductionAsync(int deviceId, DateTime date);
        Task<decimal> GetOverallQualityRateAsync(int deviceId, DateTime date);
        Task<bool> UpdateSummaryAsync(int deviceId, string ncProgram, DateTime date, int quantity, decimal qualityRate);
    }

    public class ProgramProductionSummaryRepository : Repository<ProgramProductionSummary>, IProgramProductionSummaryRepository
    {
        private readonly CNCDbContext _context;

        public ProgramProductionSummaryRepository(CNCDbContext context) : base(context)
        {
            _context = context;
        }

        public async Task<ProgramProductionSummary> GetByDeviceProgramDateAsync(int deviceId, string ncProgram, DateTime date)
        {
            return await _context.ProgramProductionSummary
                .FirstOrDefaultAsync(pps => 
                    pps.DeviceId == deviceId && 
                    pps.NCProgram == ncProgram && 
                    pps.ProductionDate.Date == date.Date);
        }

        public async Task<IEnumerable<ProgramProductionSummary>> GetByDeviceAndDateAsync(int deviceId, DateTime date)
        {
            return await _context.ProgramProductionSummary
                .Where(pps => pps.DeviceId == deviceId && pps.ProductionDate.Date == date.Date)
                .OrderBy(pps => pps.NCProgram)
                .ToListAsync();
        }

        public async Task<IEnumerable<ProgramProductionSummary>> GetByProgramAndDateRangeAsync(string ncProgram, DateTime startDate, DateTime endDate)
        {
            return await _context.ProgramProductionSummary
                .Where(pps => pps.NCProgram == ncProgram && 
                             pps.ProductionDate >= startDate && 
                             pps.ProductionDate <= endDate)
                .OrderBy(pps => pps.ProductionDate)
                .ThenBy(pps => pps.DeviceId)
                .ToListAsync();
        }

        public async Task<int> GetTotalProductionAsync(int deviceId, DateTime date)
        {
            var summaries = await GetByDeviceAndDateAsync(deviceId, date);
            return summaries.Sum(s => s.TotalQuantity);
        }

        public async Task<decimal> GetOverallQualityRateAsync(int deviceId, DateTime date)
        {
            var summaries = await GetByDeviceAndDateAsync(deviceId, date);
            
            if (summaries.Any())
            {
                var totalQuantity = summaries.Sum(s => s.TotalQuantity);
                var totalValidQuantity = summaries.Sum(s => s.ValidQuantity);
                return totalQuantity > 0 ? (decimal)totalValidQuantity / totalQuantity * 100 : 100;
            }

            return 100;
        }

        public async Task<bool> UpdateSummaryAsync(int deviceId, string ncProgram, DateTime date, int quantity, decimal qualityRate)
        {
            var summary = await GetByDeviceProgramDateAsync(deviceId, ncProgram, date);
            
            if (summary != null)
            {
                summary.TotalQuantity += quantity;
                summary.ValidQuantity = (int)(summary.TotalQuantity * qualityRate / 100);
                summary.InvalidQuantity = summary.TotalQuantity - summary.ValidQuantity;
                summary.QualityRate = qualityRate;
                
                Update(summary);
            }
            else
            {
                summary = new ProgramProductionSummary
                {
                    DeviceId = deviceId,
                    NCProgram = ncProgram,
                    ProductionDate = date,
                    TotalQuantity = quantity,
                    ValidQuantity = (int)(quantity * qualityRate / 100),
                    InvalidQuantity = quantity - (int)(quantity * qualityRate / 100),
                    QualityRate = qualityRate
                };
                
                await AddAsync(summary);
            }

            await SaveAsync();
            return true;
        }
    }
}