package com.sundot.airport.web.controller.portrait;

import com.sundot.airport.attendance.domain.AttendancePostRecord;
import com.sundot.airport.attendance.portrait.StationWorkStatsService;
import com.sundot.airport.attendance.service.IAttendancePostRecordService;
import com.sundot.airport.common.domain.portrait.IndicatorCalculateParams;
import com.sundot.airport.common.domain.portrait.ModularIndicatorResult;
import com.sundot.airport.common.enums.portrait.UserType;
import com.sundot.airport.common.exception.ServiceException;
import com.sundot.airport.common.service.portrait.ModuleIndicatorManager;
import com.sundot.airport.common.utils.DateUtils;
import com.sundot.airport.common.utils.StringUtils;
import com.sundot.airport.system.domain.vo.PositionInfoVO;
import com.sundot.airport.system.service.IBasePositionService;
import com.sundot.airport.system.service.ISysConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.spring.web.json.JacksonModuleRegistrar;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 考勤统计控制器
 * 提供考勤指标计算的REST API接口
 */
@RestController
@RequestMapping("/attendance/stats")
public class AttendanceStatsController {

    @Autowired
    private ModuleIndicatorManager moduleIndicatorManager;

    @Autowired
    private StationWorkStatsService stationWorkStatsService;

    @Autowired
    private IAttendancePostRecordService attendancePostRecordService;

    @Autowired
    private IBasePositionService basePositionService;

    @Autowired
    private ISysConfigService configService;


    /**
     * 计算站级考勤工作统计
     *
     * @param params 指标计算参数
     * @return 站级工作统计数据
     */
    @Cacheable(
            value = "attendance_station",
            keyGenerator = "statisticsKeyGenerator",
            unless = "!T(com.sundot.airport.common.cache.StatisticsCacheConditionUtil).isSuccess(#result) ||T(com.sundot.airport.common.cache.StatisticsCacheConditionUtil).isEmptyData(#result)"
    )
    @GetMapping("/station")
    public Object getStationWorkStats(IndicatorCalculateParams params) {
        return stationWorkStatsService.calculateStationWorkStats(params);
    }


    /**
     * 通道开放趋势图(折线图)
     * 通道开放数、开放时长、通道开放平均线
     */
    @Cacheable(
            value = "attendance_open_trend",
            keyGenerator = "statisticsKeyGenerator",
            unless = "!T(com.sundot.airport.common.cache.StatisticsCacheConditionUtil).isSuccess(#result) ||T(com.sundot.airport.common.cache.StatisticsCacheConditionUtil).isEmptyData(#result)"
    )
    @GetMapping("/channel/open/trend")
    public Object getChannelOpenTrend(IndicatorCalculateParams params) {
        // 处理默认时间范围（91天）
        Date startDate = params.getStartTime();
        Date endDate = params.getEndTime();

        // 如果没有提供时间范围，默认为最近91天
        if (startDate == null || endDate == null) {
            endDate = new Date();
            startDate = DateUtils.addDays(endDate, -90); // 91天包括今天
        }

        // 生成日期范围
        List<String> dateRange = generateDateRange(startDate, endDate);
        Map<String, Object> channelOpenTrend = new HashMap<>();
        // 按日期分组处理数据
        List<Map<String, Object>> trendData = new ArrayList<>();
        try {
            // 获取班次开始和结束时间
//            String startTime = configService.selectConfigByKey("attendance.post.record.start.time");
//            String endTime = configService.selectConfigByKey("attendance.post.record.end.time");
//            Date shiftStartTime = DateUtils.parseDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, startDate) + " " + startTime);
//            Date shiftEndTime = DateUtils.parseDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, DateUtils.addDays(endDate, 1)) + " " + endTime);
            String startTime = "00:00:00";
            String endTime = "23:59:59";
            Date shiftStartTime = DateUtils.parseDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, startDate) + " " + startTime);
            Date shiftEndTime = DateUtils.parseDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, endDate) + " " + endTime);

            // 一次性查询整个时间范围内的所有在岗记录
            AttendancePostRecord queryPostRecord = new AttendancePostRecord();
            queryPostRecord.setCheckInTimeStart(shiftStartTime);
            queryPostRecord.setCheckInTimeEnd(shiftEndTime);
            if (Objects.nonNull(params.getDeptId())) {
                queryPostRecord.setAttendanceBrigadeId(params.getDeptId());
            }
            List<AttendancePostRecord> postRecords = attendancePostRecordService.selectAttendancePostRecordList(queryPostRecord);


            for (String date : dateRange) {
                Map<String, Object> dataPoint = new HashMap<>();
                dataPoint.put("date", date);

                // 过滤出当前日期的数据
                List<AttendancePostRecord> currentDateRecords = filterRecordsByDate(postRecords, date);

                // 统计开放通道数
                long openChannelCount = currentDateRecords.stream()
                        .map(AttendancePostRecord::getChannelCode)
                        .filter(Objects::nonNull)
                        .count();

                // 计算总开放时长（分钟），直接使用数据库中的工作时长字段
                long totalOpenDuration = currentDateRecords.stream()
                        .filter(item -> StringUtils.isNotEmpty(item.getChannelCode()))
                        .mapToLong(record -> {
                            Long workDuration = record.getWorkDuration();
                            // 如果工作时长为null或小于等于0，则返回0
                            return workDuration != null && workDuration > 0 ? workDuration : 0;
                        })
                        .sum();


                //开放通道
                dataPoint.put("openCount", openChannelCount);
                //开放时长(小时)
                dataPoint.put("openDuration", totalOpenDuration == 0 ? 0 : new BigDecimal(totalOpenDuration).divide(new BigDecimal(60), 2, RoundingMode.HALF_UP));
                trendData.add(dataPoint);
            }
            BigDecimal divide = new BigDecimal(postRecords.size()).divide(new BigDecimal(dateRange.size()), 1, RoundingMode.HALF_UP);
            channelOpenTrend.put("avg", divide);
            channelOpenTrend.put("trend", trendData);
            return channelOpenTrend;
        } catch (Exception e) {
            throw new ServiceException("通道开放趋势计算错误: " + e.getMessage());
        }
    }

    /**
     * 根据日期过滤记录
     *
     * @param records    所有记录
     * @param targetDate 目标日期
     * @return 过滤后的记录列表
     */
    private List<AttendancePostRecord> filterRecordsByDate(List<AttendancePostRecord> records, String targetDate) {
        return records.stream()
                .filter(record -> {
                    Date attendanceDate = record.getAttendanceDate();
                    // 检查签到时间是否在目标日期
                    return attendanceDate != null && DateUtils.parseDateToStr("yyyy-MM-dd", attendanceDate).equals(targetDate);
                })
                .collect(Collectors.toList());
    }

    /**
     * 获取所有通道信息
     *
     * @return 所有通道列表
     */
    private List<PositionInfoVO> getAllChannels() {
        // 这里传入空列表表示获取所有通道
        return basePositionService.selectChannelsUnderArea(new ArrayList<>());
    }

    /**
     * 生成日期范围列表
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return 日期范围列表
     */
    private List<String> generateDateRange(Date startDate, Date endDate) {
        List<String> dateRange = new ArrayList<>();

        // 将Date转换为LocalDate
        LocalDate start = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate end = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

        // 计算天数差
        long daysBetween = ChronoUnit.DAYS.between(start, end);

        // 生成日期范围（包括起始和结束日期）
        for (int i = 0; i <= daysBetween; i++) {
            LocalDate currentDate = start.plusDays(i);
            dateRange.add(currentDate.toString());
        }

        return dateRange;
    }

}