package jnpf.attendance.schedule;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 最终排班「选人快照」：由 {@link ShiftPlanAssignmentResult} 派生，供日志按班次 / 按员工两个维度输出。
 */
public final class ShiftPlanPickSnapshot implements Serializable {

    private final List<ShiftPlanAssignmentResult.AssignedShiftBlockView> byShift;
    private final List<ShiftPlanAssignmentResult.AssignedEmployeeView> byEmployee;
    private final List<ShiftPlanAssignmentResult.IncompleteScheduleReason> incompleteScheduleReasons;

    private ShiftPlanPickSnapshot(
            List<ShiftPlanAssignmentResult.AssignedShiftBlockView> byShift,
            List<ShiftPlanAssignmentResult.AssignedEmployeeView> byEmployee,
            List<ShiftPlanAssignmentResult.IncompleteScheduleReason> incompleteScheduleReasons) {
        this.byShift =
                byShift == null
                        ? Collections.emptyList()
                        : Collections.unmodifiableList(byShift);
        this.byEmployee =
                byEmployee == null
                        ? Collections.emptyList()
                        : Collections.unmodifiableList(byEmployee);
        this.incompleteScheduleReasons =
                incompleteScheduleReasons == null
                        ? Collections.emptyList()
                        : Collections.unmodifiableList(new ArrayList<>(incompleteScheduleReasons));
    }

    public static ShiftPlanPickSnapshot from(ShiftPlanAssignmentResult result) {
        if (result == null) {
            return new ShiftPlanPickSnapshot(
                    Collections.emptyList(),
                    Collections.emptyList(),
                    Collections.emptyList());
        }
        return new ShiftPlanPickSnapshot(
                result.getByShift(),
                result.getByEmployee(),
                result.getIncompleteScheduleReasons());
    }

    public List<ShiftPlanAssignmentResult.IncompleteScheduleReason> getIncompleteScheduleReasons() {
        return incompleteScheduleReasons;
    }

    public List<ShiftPlanAssignmentResult.AssignedShiftBlockView> getByShift() {
        return byShift;
    }

    public List<ShiftPlanAssignmentResult.AssignedEmployeeView> getByEmployee() {
        return byEmployee;
    }

    public int countAssignedStaff() {
        int n = 0;
        for (ShiftPlanAssignmentResult.AssignedShiftBlockView shift : byShift) {
            for (ShiftPlanAssignmentResult.AssignedPostStaffView post : shift.getPostAssignments()) {
                n += post.getStaff().size();
            }
        }
        return n;
    }

    public int countTotalNeed() {
        int n = 0;
        for (ShiftPlanAssignmentResult.AssignedShiftBlockView shift : byShift) {
            for (ShiftPlanAssignmentResult.AssignedPostStaffView post : shift.getPostAssignments()) {
                n += post.getNeedCount();
            }
        }
        return n;
    }

    public boolean isEmpty() {
        return byShift.isEmpty();
    }

    /** pickSnap | 按班次：每个班次块 × 岗位 → 已 pick 员工列表。 */
    public String formatByShiftText() {
        if (byShift.isEmpty()) {
            return "pickSnap | 按班次 | (无数据)";
        }
        StringBuilder sb = new StringBuilder(512);
        sb.append("========== pickSnap | 按班次 ==========\n");
        for (ShiftPlanAssignmentResult.AssignedShiftBlockView shift : byShift) {
            String kind = shift.isFixedScheduling() ? "固定" : "划线";
            String shiftId =
                    shift.getShiftId() == null || shift.getShiftId().isEmpty() ? "-" : shift.getShiftId();
            for (ShiftPlanAssignmentResult.AssignedPostStaffView post : shift.getPostAssignments()) {
                sb.append("scheduleDay=")
                        .append(shift.getScheduleDay())
                        .append(" | timeRange=")
                        .append(shift.getTimeRangeText())
                        .append(" | kind=")
                        .append(kind)
                        .append(" | shiftId=")
                        .append(shiftId)
                        .append(" | postId=")
                        .append(post.getPostId())
                        .append(" | positionName=")
                        .append(post.getPositionName() == null ? "" : post.getPositionName())
                        .append(" | need=")
                        .append(post.getNeedCount())
                        .append(" | picked=")
                        .append(post.getStaff().size())
                        .append(" | pickedUsers=")
                        .append(formatPickedUsers(post.getStaff()))
                        .append('\n');
            }
        }
        return sb.toString();
    }

    /** pickSnap | 按员工：每位员工 → 已 pick 的班次列表。 */
    public String formatByEmployeeText() {
        if (byEmployee.isEmpty()) {
            return "pickSnap | 按员工 | (无数据)";
        }
        StringBuilder sb = new StringBuilder(512);
        sb.append("========== pickSnap | 按员工 ==========\n");
        for (ShiftPlanAssignmentResult.AssignedEmployeeView emp : byEmployee) {
            sb.append("userId=")
                    .append(emp.getUserId())
                    .append(" | userName=")
                    .append(emp.getUserName())
                    .append(" | shiftCount=")
                    .append(emp.getShifts().size())
                    .append('\n');
            if (emp.getShifts().isEmpty()) {
                sb.append("  (无班次)\n");
                continue;
            }
            for (ShiftPlanAssignmentResult.AssignedShiftRef s : emp.getShifts()) {
                String kind = s.isFixedScheduling() ? "固定" : "划线";
                String shiftId =
                        s.getShiftId() == null || s.getShiftId().isEmpty() ? "-" : s.getShiftId();
                sb.append("  - scheduleDay=")
                        .append(s.getScheduleDay())
                        .append(" | timeRange=")
                        .append(s.getTimeRangeText())
                        .append(" | postId=")
                        .append(s.getPostId())
                        .append(" | kind=")
                        .append(kind)
                        .append(" | shiftId=")
                        .append(shiftId)
                        .append('\n');
            }
        }
        return sb.toString();
    }

    /** 摘要 + 按班次 + 按员工。 */
    public String formatPickSnapText() {
        StringBuilder sb = new StringBuilder(1024);
        sb.append("========== pickSnap | 排班选人快照 ==========\n");
        sb.append("shiftBlockViews=")
                .append(byShift.size())
                .append(" | employees=")
                .append(byEmployee.size())
                .append(" | pickedHeadcount=")
                .append(countAssignedStaff())
                .append(" | needHeadcount=")
                .append(countTotalNeed())
                .append(" | incompleteExplanationCount=")
                .append(incompleteScheduleReasons.size())
                .append('\n');
        if (!incompleteScheduleReasons.isEmpty()) {
            sb.append(formatIncompleteReasonLinesSnippet());
        }
        sb.append(formatByShiftText()).append('\n');
        sb.append(formatByEmployeeText());
        sb.append("========== pickSnap | 结束 ==========");
        return sb.toString();
    }

    private static String formatPickedUsers(List<ShiftPlanAssignmentResult.AssignedStaffRef> staff) {
        if (staff == null || staff.isEmpty()) {
            return "(空)";
        }
        return staff.stream()
                .map(
                        s -> {
                            String tag = s.isExtra() ? "通岗" : "专岗";
                            String name =
                                    s.getUserName() == null || s.getUserName().isEmpty()
                                            ? s.getUserId()
                                            : s.getUserName();
                            return name + '(' + s.getUserId() + ")[" + tag + ']';
                        })
                        .collect(Collectors.joining(", "));
    }

    private String formatIncompleteReasonLinesSnippet() {
        StringBuilder sb = new StringBuilder(incompleteScheduleReasons.size() * 64);
        sb.append("---------- pickSnap | 不完整说明 ----------\n");
        for (ShiftPlanAssignmentResult.IncompleteScheduleReason r : incompleteScheduleReasons) {
            sb.append("scheduleDay=")
                    .append(r.getScheduleDay())
                    .append(" | code=")
                    .append(r.getReasonCode())
                    .append(" | ")
                    .append(r.getTimeRangeText() == null || r.getTimeRangeText().isEmpty()
                            ? ""
                            : "range=" + r.getTimeRangeText() + " | ")
                    .append(r.getPostId() == null || r.getPostId().isEmpty()
                            ? ""
                            : "postId=" + r.getPostId() + " | ")
                    .append("msg=")
                    .append(r.getMessage())
                    .append('\n');
        }
        return sb.toString();
    }
}
