package jnpf.attendance.service.impl.preschedule;

import jnpf.attendance.schedule.ShiftPlanAssignmentResult.AssignedEmployeeView;
import jnpf.attendance.schedule.ShiftPlanAssignmentResult.AssignedShiftRef;
import jnpf.model.attendance.vo.scheduling.PreSchedulePostVo;
import jnpf.model.attendance.vo.scheduling.PreScheduleStationVo;
import jnpf.model.attendance.vo.scheduling.PreScheduleTableRowVo;
import jnpf.model.attendance.vo.scheduling.PreScheduleTableVo;
import jnpf.model.attendance.vo.scheduling.PreScheduleUserVo;
import jnpf.util.StringUtil;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 按主表提交的岗位、工作站人员过滤 Redis 中缓存的 {@code byEmployee}：排除在 posts、stations 中均未出现的人员排班。
 */
public final class PreScheduleByEmployeeFilter {

    private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ISO_LOCAL_DATE;

    private PreScheduleByEmployeeFilter() {}

    /**
     * 排除在提交主表对应日期的 posts、stations 人员并集中均不存在的排班条目。
     */
    public static List<AssignedEmployeeView> filterByTable(
            List<AssignedEmployeeView> cached, PreScheduleTableVo table) {
        if (cached == null || cached.isEmpty()) {
            return Collections.emptyList();
        }
        Map<LocalDate, Set<String>> dayValidUsers = indexDayValidUsers(table);
        if (dayValidUsers.isEmpty()) {
            return Collections.emptyList();
        }

        List<AssignedEmployeeView> result = new ArrayList<>();
        for (AssignedEmployeeView emp : cached) {
            if (emp == null || StringUtil.isBlank(emp.getUserId())) {
                continue;
            }
            String userId = emp.getUserId().trim();
            List<AssignedShiftRef> empShifts = emp.getShifts();
            if (empShifts == null || empShifts.isEmpty()) {
                continue;
            }
            List<AssignedShiftRef> keptShifts = new ArrayList<>();
            for (AssignedShiftRef shift : empShifts) {
                if (shift == null || shift.getScheduleDay() == null) {
                    continue;
                }
                Set<String> validUsers = dayValidUsers.get(shift.getScheduleDay());
                if (validUsers != null && validUsers.contains(userId)) {
                    keptShifts.add(shift);
                }
            }
            if (!keptShifts.isEmpty()) {
                result.add(new AssignedEmployeeView(emp.getUserId(), emp.getUserName(), keptShifts));
            }
        }
        result.sort(Comparator.comparing(AssignedEmployeeView::getUserId));
        return result;
    }

    /** 每日有效人员 = 该行 posts 与 stations 中所有人员 ID 的并集。 */
    private static Map<LocalDate, Set<String>> indexDayValidUsers(PreScheduleTableVo table) {
        Map<LocalDate, Set<String>> map = new LinkedHashMap<>();
        if (table == null || table.getRows() == null) {
            return map;
        }
        for (PreScheduleTableRowVo row : table.getRows()) {
            if (row == null || StringUtil.isBlank(row.getDate())) {
                continue;
            }
            LocalDate day = parseDateQuiet(row.getDate());
            if (day == null) {
                continue;
            }
            Set<String> users = map.computeIfAbsent(day, k -> new HashSet<>());
            indexPostsUsers(users, row.getPosts());
            indexStationsUsers(users, row.getStations());
        }
        return map;
    }

    private static void indexPostsUsers(Set<String> users, List<PreSchedulePostVo> posts) {
        if (posts == null) {
            return;
        }
        for (PreSchedulePostVo post : posts) {
            if (post == null) {
                continue;
            }
            addUsers(users, post.getUsers());
        }
    }

    private static void indexStationsUsers(Set<String> users, List<PreScheduleStationVo> stations) {
        if (stations == null) {
            return;
        }
        for (PreScheduleStationVo station : stations) {
            if (station == null) {
                continue;
            }
            addUsers(users, station.getUsers());
        }
    }

    private static void addUsers(Set<String> users, List<PreScheduleUserVo> list) {
        if (list == null) {
            return;
        }
        for (PreScheduleUserVo user : list) {
            if (user != null && StringUtil.isNotBlank(user.getId())) {
                users.add(user.getId().trim());
            }
        }
    }

    private static LocalDate parseDateQuiet(String text) {
        try {
            return LocalDate.parse(text.trim(), DATE_FMT);
        } catch (DateTimeParseException ex) {
            return null;
        }
    }
}
