using System;
using System.Collections.Generic;
using System.Linq;
using Dapper;
using CncModels.Entity;
using CncModels.Dto.Production;
using CncModels.Dto;
using CncRepository.Base;
using CncRepository.Interface;

namespace CncRepository.Impl
{
    /// <summary>
    /// cnc_daily_production 产量仓储实现（业务库）
    /// </summary>
    public class DailyProductionRepository : BusinessRepository, IDailyProductionRepository
    {
        public DailyProductionRepository(string connectionString) : base(connectionString) { }

        public DailyProduction GetById(int id)
        {
            using (var conn = CreateConnection())
            {
                string sql = "SELECT * FROM cnc_daily_production WHERE id = @Id";
                return conn.QuerySingleOrDefault<DailyProduction>(sql, new { Id = id });
            }
        }

        public PagedResult<DailyProductionListItem> GetList(ProductionQuery query)
        {
            using (var conn = CreateConnection())
            {
                // 混合查询：已汇总日期用daily_production，未汇总日期从segment实时计算
                string baseSql = @"
                    SELECT dp.id, dp.machine_id AS MachineId, m.name AS MachineName, dp.production_date AS ProductionDate, 
                           dp.program_name AS ProgramName, dp.total_quantity AS TotalQuantity, dp.segment_count AS SegmentCount, 
                           dp.total_run_time AS TotalRunTime, dp.total_cutting_time AS TotalCuttingTime, dp.total_cycle_time AS TotalCycleTime
                    FROM cnc_daily_production dp
                    LEFT JOIN cnc_machine m ON dp.machine_id = m.id
                    WHERE 1=1";
                string realtimeSql = @"
                    SELECT 0 AS Id, seg.machine_id AS MachineId, m.name AS MachineName, seg.production_date AS ProductionDate, 
                           seg.program_name AS ProgramName,
                           SUM(CASE WHEN seg.is_settled=1 THEN seg.quantity 
                                ELSE COALESCE(seg.end_part_count, seg.start_part_count) - seg.start_part_count END) AS TotalQuantity,
                           COUNT(*) AS SegmentCount,
                           cr_runtime.run_hours AS TotalRunTime,
                           cr_runtime.cut_hours AS TotalCuttingTime,
                           NULL AS TotalCycleTime
                    FROM cnc_production_segment seg
                    LEFT JOIN cnc_machine m ON seg.machine_id = m.id
                    LEFT JOIN (
                        SELECT cr.machine_id, DATE(cr.collect_time) AS d,
                               COALESCE(ROUND(SUM(max_min.delta)/3600,1), 0) AS run_hours,
                               COALESCE(ROUND(SUM(max_min.delta)/3600,1), 0) AS cut_hours
                        FROM cnc_collect_record cr
                        JOIN (
                            SELECT machine_id, DATE(collect_time) AS dd, MAX(cutting_time)-MIN(cutting_time) AS delta
                            FROM cnc_collect_record GROUP BY machine_id, DATE(collect_time)
                        ) max_min ON cr.machine_id = max_min.machine_id AND DATE(cr.collect_time) = max_min.dd
                        GROUP BY cr.machine_id, DATE(cr.collect_time)
                    ) cr_runtime ON cr_runtime.machine_id = seg.machine_id AND cr_runtime.d = seg.production_date
                    WHERE NOT EXISTS (
                        SELECT 1 FROM cnc_daily_production dp 
                        WHERE dp.machine_id = seg.machine_id AND dp.production_date = seg.production_date
                    )";

                var parameters = new DynamicParameters();
                // 日期过滤
                if (query?.StartDate.HasValue == true)
                {
                    baseSql += " AND dp.production_date >= @StartDate";
                    realtimeSql += " AND seg.production_date >= @StartDate";
                    parameters.Add("StartDate", query.StartDate);
                }
                if (query?.EndDate.HasValue == true)
                {
                    baseSql += " AND dp.production_date <= @EndDate";
                    realtimeSql += " AND seg.production_date <= @EndDate";
                    parameters.Add("EndDate", query.EndDate);
                }
                // 兼容旧的单日期查询
                if (query?.Date.HasValue == true && query.StartDate == null)
                {
                    baseSql += " AND dp.production_date = @Date";
                    realtimeSql += " AND seg.production_date = @Date";
                    parameters.Add("Date", query.Date);
                }
                // 车间过滤
                if (query?.WorkshopId.HasValue == true)
                {
                    baseSql += " AND m.workshop_id = @WorkshopId";
                    realtimeSql += " AND m.workshop_id = @WorkshopId";
                    parameters.Add("WorkshopId", query.WorkshopId);
                }
                // 机床过滤
                if (query?.MachineId.HasValue == true)
                {
                    baseSql += " AND dp.machine_id = @MachineId";
                    realtimeSql += " AND seg.machine_id = @MachineId";
                    parameters.Add("MachineId", query.MachineId);
                }
                // 工人过滤（通过worker_machine关联表）
                if (query?.WorkerId.HasValue == true)
                {
                    baseSql += " AND EXISTS (SELECT 1 FROM cnc_worker_machine wm WHERE wm.machine_id = dp.machine_id AND wm.worker_id = @WorkerId)";
                    realtimeSql += " AND EXISTS (SELECT 1 FROM cnc_worker_machine wm WHERE wm.machine_id = seg.machine_id AND wm.worker_id = @WorkerId)";
                    parameters.Add("WorkerId", query.WorkerId);
                }

                realtimeSql += " GROUP BY seg.machine_id, seg.production_date, seg.program_name, m.name";

                string unionSql = $"{baseSql} UNION ALL {realtimeSql}";
                string countSql = $"SELECT COUNT(*) FROM ({unionSql}) AS t";

                int offset = (query.Page - 1) * query.PageSize;
                string paging = $" ORDER BY ProductionDate DESC, MachineName LIMIT @Limit OFFSET @Offset";
                parameters.Add("Limit", query.PageSize);
                parameters.Add("Offset", offset);

                var items = conn.Query<DailyProductionListItem>(unionSql + paging, parameters).ToList();
                int total = conn.ExecuteScalar<int>(countSql, parameters);
                return new PagedResult<DailyProductionListItem>
                {
                    Items = items,
                    Total = total,
                    Page = query.Page,
                    PageSize = query.PageSize
                };
            }
        }

        public List<DailyProduction> GetByMachineAndDate(int machineId, DateTime date)
        {
            using (var conn = CreateConnection())
            {
                string sql = "SELECT * FROM cnc_daily_production WHERE machine_id = @MachineId AND production_date = @Date";
                return conn.Query<DailyProduction>(sql, new { MachineId = machineId, Date = date }).ToList();
            }
        }

        public List<DailyProduction> GetByDateRange(DateTime startDate, DateTime endDate)
        {
            using (var conn = CreateConnection())
            {
                string sql = @"SELECT dp.* FROM cnc_daily_production dp LEFT JOIN cnc_machine m ON dp.machine_id = m.id WHERE dp.production_date BETWEEN @Start AND @End ORDER BY dp.production_date DESC";
                return conn.Query<DailyProduction>(sql, new { Start = startDate, End = endDate }).ToList();
            }
        }

        public decimal GetTotalByDateRange(DateTime startDate, DateTime endDate, int? workshopId)
        {
            using (var conn = CreateConnection())
            {
                string sql = @"SELECT SUM(dp.total_quantity) FROM cnc_daily_production dp LEFT JOIN cnc_machine m ON dp.machine_id = m.id WHERE dp.production_date BETWEEN @Start AND @End";
                if (workshopId.HasValue)
                {
                    sql += " AND m.workshop_id = @WorkshopId";
                    return conn.ExecuteScalar<decimal>(sql, new { Start = startDate, End = endDate, WorkshopId = workshopId.Value });
                }
                return conn.ExecuteScalar<decimal>(sql, new { Start = startDate, End = endDate });
            }
        }

        public decimal GetTotalByWorkerAndDateRange(int workerId, DateTime startDate, DateTime endDate)
        {
            using (var conn = CreateConnection())
            {
                string sql = @"SELECT SUM(total_quantity) FROM cnc_daily_production WHERE production_date BETWEEN @Start AND @End";
                var res = conn.ExecuteScalar<decimal?>(sql, new { Start = startDate, End = endDate });
                return res ?? 0m;
            }
        }

        public List<DailyProduction> GetMachineRankByDateRange(DateTime startDate, DateTime endDate, int top)
        {
            using (var conn = CreateConnection())
            {
                string sql = @"SELECT m.id AS Id, m.id AS MachineId, m.name AS MachineName, SUM(dp.total_quantity) AS TotalQuantity, NULL AS ProgramName, NULL AS ProductionDate, NULL AS SegmentCount, NULL AS TotalRunTime, NULL AS TotalCuttingTime, NULL AS TotalCycleTime
                                FROM cnc_daily_production dp
                                JOIN cnc_machine m ON dp.machine_id = m.id
                                WHERE dp.production_date BETWEEN @Start AND @End
                                GROUP BY m.id, m.name
                                ORDER BY SUM(dp.total_quantity) DESC LIMIT @Top";
                return conn.Query<DailyProduction>(sql, new { Start = startDate, End = endDate, Top = top }).ToList();
            }
        }

        public List<DailyProduction> GetWorkerRankByDateRange(DateTime startDate, DateTime endDate, int top)
        {
            using (var conn = CreateConnection())
            {
                string sql = @"SELECT 0 AS Id, NULL AS MachineId, NULL AS MachineName, SUM(total_quantity) AS TotalQuantity, NULL AS ProductionDate, NULL AS ProgramName, NULL AS SegmentCount, NULL AS TotalRunTime, NULL AS TotalCuttingTime, NULL AS TotalCycleTime
                                FROM cnc_daily_production
                                WHERE production_date BETWEEN @Start AND @End
                                GROUP BY machine_id
                                ORDER BY SUM(total_quantity) DESC LIMIT @Top";
                return conn.Query<DailyProduction>(sql, new { Start = startDate, End = endDate, Top = top }).ToList();
            }
        }
    }
}
