package com.aegis.emergency.duty.service.impl;

import java.time.LocalDate;
import java.time.LocalTime;
import com.aegis.common.utils.DateUtils;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Collections;
import java.util.Map;
import java.util.stream.Collectors;
import java.io.Serializable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.aegis.common.exception.ServiceException;
import com.aegis.common.utils.SecurityUtils;
import com.aegis.common.utils.StringUtils;
import com.aegis.emergency.duty.constant.DutyShiftStatus;
import com.aegis.emergency.duty.constant.DutyShiftType;
import com.aegis.emergency.duty.domain.DutyShift;
import com.aegis.emergency.duty.domain.DutyShiftMember;
import com.aegis.emergency.duty.mapper.DutyShiftMapper;
import com.aegis.emergency.duty.service.DutyShiftService;
import com.aegis.emergency.duty.service.DutyShiftMemberService;

/**
 * 值班排班Service业务层处理
 * 
 * @author aegis
 */
@Service
public class DutyShiftServiceImpl extends ServiceImpl<DutyShiftMapper, DutyShift> implements DutyShiftService {

    /** 时间格式常量：HH:mm:ss */
    private static final String TIME_FORMAT = "HH:mm:ss";

    @Autowired
    private DutyShiftMemberService shiftMemberService;

    /**
     * 查询排班列表
     * 
     * @param shift 排班信息
     * @return 排班集合
     */
    @Override
    public List<DutyShift> listByCondition(DutyShift condition) {
        LambdaQueryWrapper<DutyShift> wrapper = new LambdaQueryWrapper<>();
        if (condition != null) {
            // 日期范围查询（优先于精确日期查询）
            if (condition.getBeginShiftDate() != null && condition.getEndShiftDate() != null) {
                wrapper.between(DutyShift::getShiftDate, condition.getBeginShiftDate(), condition.getEndShiftDate());
            } else if (condition.getBeginShiftDate() != null) {
                // 只有开始日期
                wrapper.ge(DutyShift::getShiftDate, condition.getBeginShiftDate());
            } else if (condition.getEndShiftDate() != null) {
                // 只有结束日期
                wrapper.le(DutyShift::getShiftDate, condition.getEndShiftDate());
            } else if (condition.getShiftDate() != null) {
                // 精确日期查询（当没有范围查询时）
                wrapper.eq(DutyShift::getShiftDate, condition.getShiftDate());
            }
            
            if (StringUtils.isNotEmpty(condition.getShiftType())) {
                wrapper.eq(DutyShift::getShiftType, condition.getShiftType());
            }
            if (StringUtils.isNotEmpty(condition.getStatus())) {
                wrapper.eq(DutyShift::getStatus, condition.getStatus());
            }
        }
        wrapper.eq(DutyShift::getDelFlag, "0");
        wrapper.orderByDesc(DutyShift::getShiftDate);

        List<DutyShift> list = list(wrapper);
        fillShiftMembers(list);
        return list;
    }

    /**
     * 根据ID查询排班
     * 
     * @param id 排班ID
     * @return 排班信息
     */
    @Override
    public DutyShift getById(Serializable id) {
        DutyShift shift = super.getById(id);
        if (shift == null || "2".equals(shift.getDelFlag())) {
            return null;
        }
        fillShiftMembers(Collections.singletonList(shift));
        return shift;
    }

    /**
     * 查询当前正在值班的排班
     * 
     * @return 当前排班信息，如果当前时间段无人值班则返回null
     */
    @Override
    public DutyShift getCurrentShift() {
        // 获取当前日期和时间
        LocalDate today = LocalDate.now();
        LocalTime currentTime = LocalTime.now();
        Date todayDate = java.sql.Date.valueOf(today);
        Date yesterdayDate = java.sql.Date.valueOf(today.minusDays(1));

        // 查询今天的有效排班
        LambdaQueryWrapper<DutyShift> todayWrapper = new LambdaQueryWrapper<>();
        todayWrapper.eq(DutyShift::getShiftDate, todayDate)
                    .eq(DutyShift::getStatus, DutyShiftStatus.ACTIVE.getCode())
                    .eq(DutyShift::getDelFlag, "0");
        List<DutyShift> todayShifts = list(todayWrapper);

        // 查询昨天的有效排班（用于检查可能仍在进行的夜班）
        LambdaQueryWrapper<DutyShift> yesterdayWrapper = new LambdaQueryWrapper<>();
        yesterdayWrapper.eq(DutyShift::getShiftDate, yesterdayDate)
                        .eq(DutyShift::getStatus, DutyShiftStatus.ACTIVE.getCode())
                        .eq(DutyShift::getDelFlag, "0");
        List<DutyShift> yesterdayShifts = list(yesterdayWrapper);

        // 合并两个列表
        List<DutyShift> allShifts = new ArrayList<>();
        allShifts.addAll(todayShifts);
        allShifts.addAll(yesterdayShifts);

        if (allShifts.isEmpty()) {
            return null;
        }

        // 查找当前时间在时间范围内的排班
        for (DutyShift shift : allShifts) {
            if (StringUtils.isEmpty(shift.getStartTime()) || StringUtils.isEmpty(shift.getEndTime())) {
                continue;
            }

            try {
                LocalTime startTime = DateUtils.parseTime(shift.getStartTime(), TIME_FORMAT);
                LocalTime endTime = DateUtils.parseTime(shift.getEndTime(), TIME_FORMAT);
                
                // Convert shiftDate to LocalDate for reliable comparison
                LocalDate shiftDate = shift.getShiftDate().toInstant()
                    .atZone(java.time.ZoneId.systemDefault())
                    .toLocalDate();
                boolean isToday = shiftDate.equals(today);

                boolean isWithinRange;
                if (endTime.isBefore(startTime)) {
                    // 跨天班次（夜班：如 20:00 - 08:00）
                    if (isToday) {
                        // 今天的夜班：当前时间 >= 开始时间 或 当前时间 <= 结束时间
                        isWithinRange = currentTime.isAfter(startTime) || currentTime.isBefore(endTime) || currentTime.equals(startTime);
                    } else {
                        // 昨天的夜班：只检查当前时间 <= 结束时间（仍在进行中）
                        isWithinRange = currentTime.isBefore(endTime) || currentTime.equals(endTime);
                    }
                } else {
                    // 正常班次（只检查今天的班次）
                    if (isToday) {
                        // 当前时间在开始时间和结束时间之间
                        isWithinRange = (currentTime.isAfter(startTime) || currentTime.equals(startTime)) 
                                       && (currentTime.isBefore(endTime) || currentTime.equals(endTime));
                    } else {
                        // 跳过昨天的正常班次（已经结束）
                        continue;
                    }
                }

                if (isWithinRange) {
                    fillShiftMembers(Collections.singletonList(shift));
                    return shift;
                }
            } catch (Exception e) {
                // 时间格式解析失败，跳过该排班
                continue;
            }
        }

        return null; // 当前时间段无人值班
    }

    @Override
    @Transactional
    public boolean save(DutyShift shift) {
        if (shift == null) {
            throw new ServiceException("排班信息不能为空");
        }
        if (shift.getShiftDate() == null) {
            throw new ServiceException("排班日期不能为空");
        }
        
        // 验证班次类型
        if (StringUtils.isNotEmpty(shift.getShiftType())) {
            if (DutyShiftType.fromCode(shift.getShiftType()) == null) {
                throw new ServiceException("班次类型无效，可选值：day-白班，night-夜班，all-全天");
            }
        }
        
        // 验证状态
        if (StringUtils.isNotEmpty(shift.getStatus())) {
            if (DutyShiftStatus.fromCode(shift.getStatus()) == null) {
                throw new ServiceException("排班状态无效，可选值：active-有效，cancelled-已取消");
            }
        }
        
        String operator = SecurityUtils.getUsername();
        shift.setCreateBy(operator);
        shift.setCreateTime(new Date());
        shift.setUpdateBy(operator);
        shift.setUpdateTime(new Date());
        
        // 设置默认值
        if (StringUtils.isEmpty(shift.getStatus())) {
            shift.setStatus(DutyShiftStatus.ACTIVE.getCode());
        }
        if (StringUtils.isEmpty(shift.getDelFlag())) {
            shift.setDelFlag("0");
        }
        
        // 检查时间重叠
        checkShiftOverlap(shift, null);
        
        return super.save(shift);
    }

    /**
     * 修改排班
     * 
     * @param shift 排班信息
     * @return 结果
     */
    @Override
    @Transactional
    public boolean updateById(DutyShift shift) {
        if (shift == null || shift.getId() == null) {
            throw new ServiceException("排班信息或ID不能为空");
        }
        
        // 检查排班是否存在
        DutyShift existingShift = getById(shift.getId());
        if (existingShift == null) {
            throw new ServiceException("排班不存在或已删除");
        }
        
        // 验证班次类型
        if (StringUtils.isNotEmpty(shift.getShiftType())) {
            if (DutyShiftType.fromCode(shift.getShiftType()) == null) {
                throw new ServiceException("班次类型无效，可选值：day-白班，night-夜班，all-全天");
            }
        }
        
        // 验证状态
        if (StringUtils.isNotEmpty(shift.getStatus())) {
            if (DutyShiftStatus.fromCode(shift.getStatus()) == null) {
                throw new ServiceException("排班状态无效，可选值：active-有效，cancelled-已取消");
            }
        }
        
        String operator = SecurityUtils.getUsername();
        shift.setUpdateBy(operator);
        shift.setUpdateTime(new Date());
        
        // 检查时间重叠（排除当前排班）
        checkShiftOverlap(shift, shift.getId());
        
        return super.updateById(shift);
    }

    @Override
    @Transactional
    public boolean removeById(Serializable id) {
        if (id == null) {
            throw new ServiceException("排班ID不能为空");
        }

        Long shiftId = (Long) id;
        DutyShift shift = getById(shiftId);
        if (shift == null) {
            throw new ServiceException("排班不存在或已删除");
        }

        // 级联删除排班成员
        shiftMemberService.removeByShiftId(shiftId);

        // 逻辑删除排班
        shift.setDelFlag("2");
        String operator = SecurityUtils.getUsername();
        shift.setUpdateBy(operator);
        shift.setUpdateTime(new Date());

        return super.updateById(shift);
    }

    /**
     * 批量填充排班的成员信息、主值班人等附加字段
     */
    private void fillShiftMembers(List<DutyShift> shifts) {
        if (shifts == null || shifts.isEmpty()) {
            return;
        }
        List<Long> shiftIds = shifts.stream()
            .filter(item -> item != null && item.getId() != null)
            .map(DutyShift::getId)
            .collect(Collectors.toList());
        if (shiftIds.isEmpty()) {
            return;
        }

        List<DutyShiftMember> allMembers = shiftMemberService.listByShiftIds(shiftIds);
        Map<Long, List<DutyShiftMember>> memberMap = allMembers.stream()
            .collect(Collectors.groupingBy(DutyShiftMember::getShiftId));

        for (DutyShift shift : shifts) {
            if (shift == null || shift.getId() == null) {
                continue;
            }
            List<DutyShiftMember> members = memberMap.getOrDefault(shift.getId(), Collections.emptyList());
            shift.setMembers(members);
            shift.setMemberCount(members.size());

            DutyShiftMember lead = members.stream()
                .filter(member -> StringUtils.equals(member.getRole(), "leader"))
                .findFirst()
                .orElse(null);
            shift.setLeadName(lead != null ? lead.getMemberName() : null);
            shift.setLeadPhone(lead != null ? lead.getPhone() : null);
        }
    }

    /**
     * 检查排班时间是否与已有排班重叠
     * 
     * @param newShift 新排班信息
     * @param excludeShiftId 排除的排班ID（更新时使用，避免与自身比较）
     */
    private void checkShiftOverlap(DutyShift newShift, Long excludeShiftId) {
        if (StringUtils.isEmpty(newShift.getStartTime()) || StringUtils.isEmpty(newShift.getEndTime())) {
            return; // 没有时间信息，无法检查重叠
        }

        // 只检查有效状态的排班
        if (!DutyShiftStatus.ACTIVE.getCode().equals(newShift.getStatus())) {
            return; // 非有效状态，不需要检查重叠
        }

        // 查询同一天的有效排班
        LambdaQueryWrapper<DutyShift> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DutyShift::getShiftDate, newShift.getShiftDate())
               .eq(DutyShift::getStatus, DutyShiftStatus.ACTIVE.getCode())
               .eq(DutyShift::getDelFlag, "0");
        
        if (excludeShiftId != null) {
            wrapper.ne(DutyShift::getId, excludeShiftId); // 更新时排除当前排班
        }
        
        List<DutyShift> existingShifts = list(wrapper);
        if (existingShifts.isEmpty()) {
            return; // 没有已有排班，无重叠
        }

        // 解析新排班的时间
        LocalTime newStart;
        LocalTime newEnd;
        try {
            newStart = DateUtils.parseTime(newShift.getStartTime(), TIME_FORMAT);
            newEnd = DateUtils.parseTime(newShift.getEndTime(), TIME_FORMAT);
        } catch (Exception e) {
            // 时间格式错误，跳过检查
            return;
        }
        boolean newIsNightShift = newEnd.isBefore(newStart);

        // 检查与每个已有排班是否重叠
        for (DutyShift existing : existingShifts) {
            if (StringUtils.isEmpty(existing.getStartTime()) || StringUtils.isEmpty(existing.getEndTime())) {
                continue;
            }

            try {
                LocalTime existingStart = DateUtils.parseTime(existing.getStartTime(), TIME_FORMAT);
                LocalTime existingEnd = DateUtils.parseTime(existing.getEndTime(), TIME_FORMAT);
                boolean existingIsNightShift = existingEnd.isBefore(existingStart);

                if (isTimeRangeOverlap(newStart, newEnd, newIsNightShift, existingStart, existingEnd, existingIsNightShift)) {
                    throw new ServiceException(String.format(
                        "排班时间冲突：%s %s ~ %s 与已有排班 %s %s ~ %s 时间重叠",
                        DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, newShift.getShiftDate()),
                        newShift.getStartTime(), newShift.getEndTime(),
                        DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, existing.getShiftDate()),
                        existing.getStartTime(), existing.getEndTime()
                    ));
                }
            } catch (ServiceException e) {
                // 重新抛出业务异常（重叠冲突）
                throw e;
            } catch (Exception e) {
                // 时间解析失败，跳过该排班（记录日志但不中断流程）
                continue;
            }
        }
    }

    /**
     * 判断两个时间段是否重叠
     * 
     * @param start1 第一个时间段的开始时间
     * @param end1 第一个时间段的结束时间
     * @param isNight1 第一个时间段是否为夜班（跨天）
     * @param start2 第二个时间段的开始时间
     * @param end2 第二个时间段的结束时间
     * @param isNight2 第二个时间段是否为夜班（跨天）
     * @return true表示重叠，false表示不重叠
     */
    private boolean isTimeRangeOverlap(LocalTime start1, LocalTime end1, boolean isNight1,
                                       LocalTime start2, LocalTime end2, boolean isNight2) {
        // 两个都是正常班次（不跨天）
        if (!isNight1 && !isNight2) {
            // 重叠条件：start1 < end2 && start2 < end1
            return (start1.isBefore(end2) || start1.equals(end2)) 
                && (start2.isBefore(end1) || start2.equals(end1));
        }
        
        // 两个都是夜班（跨天）- 同一天的夜班总是重叠
        if (isNight1 && isNight2) {
            return true;
        }
        
        // 一个是夜班，一个是正常班次
        if (isNight1) {
            // start1-end1是夜班（如20:00-08:00），start2-end2是正常班次（如08:00-18:00）
            // 夜班覆盖：从start1（今天）到次日end1
            // 在同一天，正常班次与夜班重叠的条件：
            // 1. 正常班次开始时间 >= 夜班开始时间（如20:00-22:00与20:00-08:00重叠）
            // 2. 正常班次结束时间 > 夜班开始时间（如18:00-22:00与20:00-08:00重叠）
            // 注意：夜班结束时间在次日，所以同一天的正常班次不会与夜班结束时间重叠
            return (start2.isAfter(start1) || start2.equals(start1)) 
                || (end2.isAfter(start1) || end2.equals(start1));
        } else {
            // start1-end1是正常班次，start2-end2是夜班
            // 正常班次与夜班重叠的条件：
            // 1. 正常班次开始时间 >= 夜班开始时间（如20:00-22:00与20:00-08:00重叠）
            // 2. 正常班次结束时间 > 夜班开始时间（如18:00-22:00与20:00-08:00重叠）
            return (start1.isAfter(start2) || start1.equals(start2)) 
                || (end1.isAfter(start2) || end1.equals(start2));
        }
    }
}