package com.kingdee.eas.custom.szpgm.osf.service;

import com.kingdee.bos.BOSException;
import com.kingdee.bos.Context;
import com.kingdee.bos.bsf.service.app.IHRMsfService;
import com.kingdee.eas.common.EASBizException;
import com.kingdee.eas.util.app.DbUtil;
import com.kingdee.jdbc.rowset.IRowSet;
import org.apache.commons.lang3.StringUtils;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 员工兼职信息查询OSF服务
 * <p>
 *     实现 {@link IHRMsfService} 接口，提供员工兼职信息的分页查询功能。
 *     支持按员工编号（精确）、最后修改时间进行过滤筛选。
 *     同一员工存在多个上级时，会将上级编码合并到一个列表中返回。
 * </p>
 *
 * <h3>关联数据表</h3>
 * <ul>
 *     <li><b>T_HR_PluralityAddBizBillEntry</b>（pae）—— 员工加入兼职单分录表，主表</li>
 *     <li><b>T_HR_PluralityAddBizBill</b>（pa）—— 员工加入兼职单表，获取审批状态</li>
 *     <li><b>T_HR_PluralityDelBizBillentry</b>（pde）—— 员工移除兼职单分录表，获取结束日期</li>
 *     <li><b>T_HR_PluralityDelBizBill</b>（pd）—— 员工移除兼职单表，获取移除审批状态</li>
 *     <li><b>t_bd_person</b>（pe）—— 员工基础信息表，取员工编号</li>
 *     <li><b>t_org_position</b>（pos）—— 岗位表，取兼职岗位信息</li>
 *     <li><b>t_org_admin</b>（org）—— 行政组织表</li>
 *     <li><b>T_HR_EMPPOSTEXPERIENCEHIS</b>（phis）—— 岗位任职历史表，通过上级岗位取当前上级</li>
 *     <li><b>t_bd_person</b>（ppe）—— 员工基础信息表（二次关联，取上级员工信息）</li>
 * </ul>
 *
 * <h3>入参说明</h3>
 * <ul>
 *     <li><b>modifyDate</b>（String，可选）—— 最后修改日期（格式yyyy-MM-dd），筛选该日期之后修改的兼职记录（增量同步场景）</li>
 *     <li><b>startDate</b>（String，可选）—— 生效开始日期（格式yyyy-MM-dd），筛选在该日期之后仍有效的兼职记录，即兼职未结束或结束日期>=此日期</li>
 *     <li><b>endDate</b>（String，可选）—— 生效结束日期（格式yyyy-MM-dd），筛选兼职开始日期<=此日期的记录</li>
 *     <li><b>personCode</b>（String，可选）—— 员工编号，精确匹配</li>
 *     <li><b>page</b>（int/String，可选，默认1）—— 页码</li>
 *     <li><b>size</b>（int/String，可选，默认100，上限1000）—— 每页条数</li>
 * </ul>
 *
 * <h3>返回结果</h3>
 * <pre>{@code
 * {
 *     "msg": "成功",
 *     "code": "200",
 *     "page": 1,
 *     "size": 100,
 *     "data": [{
 *         "id": "分录主键",
 *         "personid": "员工ID",
 *         "personCode": "员工编号",
 *         "startDate": "兼职开始日期（yyyy-MM-dd）",
 *         "endDate": "兼职结束日期（yyyy-MM-dd），未结束则为2199-12-31",
 *         "orgCode": "兼职组织编码",
 *         "posCode": "兼职岗位编码",
 *         "leader": ["上级员工编码列表"],
 *         "description": "兼职备注"
 *     }]
 * }
 * }</pre>
 *
 * <h3>业务规则</h3>
 * <ul>
 *     <li>只查询加入兼职单审批通过的记录（pa.fbillstate=3）</li>
 *     <li>兼职结束日期：只有移除兼职单审批通过（pd.fbillstate=3）时才取实际结束日期，否则返回"2199-12-31"表示未结束</li>
 * </ul>
 *
 * @author szpgm
 * @since 2026/07/02
 */
public class GetPluralityInfoOsfService implements IHRMsfService {

    /**
     * 处理员工兼职信息查询请求
     *
     * @param context EAS上下文对象，用于执行数据库查询
     * @param map     入参Map，包含过滤条件和分页参数
     * @return Map 包含查询结果、状态码和分页信息
     * @throws EASBizException 业务异常
     * @throws BOSException    平台异常
     */
    @Override
    public Object process(Context context, Map map) throws EASBizException, BOSException {
        // 返回结果容器
        Map<String, Object> result = new HashMap<String, Object>();
        List<Map<String, Object>> list = new ArrayList<>();

        // ==================== 入参解析 ====================

        // 最后修改日期（格式：yyyy-MM-dd），同时检查加入兼职表和移除兼职表（增量同步场景）
        String modifyDate = (String) map.get("modifyDate");
        // 生效开始日期（格式：yyyy-MM-dd），筛选兼职未结束或结束日期>=此日期的记录
        String startDateStr = (String) map.get("startDate");
        // 生效结束日期（格式：yyyy-MM-dd），筛选兼职开始日期<=此日期的记录
        String endDateStr = (String) map.get("endDate");
        // 员工编号（精确匹配）
        String code = (String) map.get("personCode");

        // 每页条数（默认100，上限1000）
        int maxSize = 1000;
        int size = 100;
        if (map.get("size") != null) {
            if (map.get("size") instanceof Integer) {
                size = (int) map.get("size");
            } else if (map.get("size") instanceof String) {
                size = Integer.parseInt((String) map.get("size"));
            }
            size = Math.min(maxSize, size);
        }

        // 页码（默认1）
        int page = 1;
        if (map.get("page") != null) {
            if (map.get("page") instanceof Integer) {
                page = (int) map.get("page");
            } else if (map.get("page") instanceof String) {
                page = Integer.parseInt((String) map.get("page"));
            }
        }

        // ==================== 查询数据 ====================
        try {
            // 初始化成功响应
            result.put("msg", "成功");
            result.put("code", "200");
            result.put("page", page);
            result.put("size", size);
            result.put("data", list);

            // 构建基础SQL，动态追加过滤条件
            StringBuilder sql = getSql();
            // SQL参数列表（与?占位符一一对应）
            List<Object> paramArr = new ArrayList<>();

            // 修改日期过滤（增量同步）：加入兼职单或移除兼职单的最后修改时间 >= 指定日期
            if (StringUtils.isNotBlank(modifyDate)) {
                sql.append(" and (pa.flastupdatetime >= ? or pd.flastupdatetime >= ?) ");
                paramArr.add(modifyDate);
                paramArr.add(modifyDate);
            }

            // 生效开始日期过滤：筛选在该日期之后仍有兼职效力的记录
            // 即：移除兼职单未审批通过（兼职未结束，视为2199-12-31），或结束日期 >= startDate
            if (StringUtils.isNotBlank(startDateStr)) {
                sql.append(" and (pd.fbillstate is null or pd.fbillstate != 3 or pde.fbizdate >= ?) ");
                paramArr.add(startDateStr);
            }

            // 生效结束日期过滤：筛选兼职开始日期 <= endDate 的记录
            if (StringUtils.isNotBlank(endDateStr)) {
                sql.append(" and pae.fbizdate <= ? ");
                paramArr.add(endDateStr);
            }

            // 员工编号精确匹配
            if (StringUtils.isNotBlank(code)) {
                sql.append(" and pe.fnumber = ? ");
                paramArr.add(code);
            }

            // 分页：LIMIT 返回条数 OFFSET 跳过条数
            sql.append(" order by pae.fpersonid desc LIMIT ? OFFSET ? ");
            paramArr.add(size);
            paramArr.add(((page - 1) * size));

            // 执行SQL查询
            IRowSet rs = DbUtil.executeQuery(context, sql.toString(), paramArr.toArray());
            // 以员工ID为key的Map，用于合并同一员工的多条记录（一个员工可能有多个上级）
            Map<String, Map<String, Object>> maps = new HashMap<>();
            // 日期格式化器（yyyy-MM-dd）
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

            // 遍历结果集，将同一员工的多行数据合并为一条记录
            while (rs.next()) {
                String id = rs.getString("personid");
                Map<String, Object> param = new HashMap<>();
//                Map<String, Object> param = maps.get(id);
//                // 首次遇到该员工时，初始化记录并创建上级编码列表
//                if (null == param) {
//                    param = new HashMap<>();
//                    List<String> leaderIds = new ArrayList<>();
//                    param.put("leader", leaderIds);
//                    maps.put(id, param);
//                }
//                // 收集该员工的所有上级编码（多行数据的共同字段会覆盖，但值相同）
//                List<String> leader = (List<String>) param.get("leader");
//                leader.add(rs.getString("leader"));

                // ---- 员工基本信息 ----
                param.put("id", rs.getString("id"));
                // 员工ID
                param.put("personid", id);
                String leaderStr = rs.getString("leader");
                List<String> leaders = new ArrayList<>();
                if(StringUtils.isNotBlank(leaderStr)){
                    leaders.addAll(Arrays.asList(leaderStr.split(",")));
                }
                param.put("leader", leaders);
                param.put("personCode", rs.getString("personCode"));
                // ---- 兼职日期（Date -> String 格式化） ----
                // 兼职开始日期
                Date startDate = rs.getDate("startDate");
                param.put("startDate", (null != startDate ? sdf.format(startDate) : null));

                // 移除兼职单审批状态（3表示审批通过）
                int pdbillstate = rs.getInt("pdbillstate");
                // 兼职结束日期：只有移除兼职单审批通过时才取实际结束日期，否则返回"2199-12-31"表示兼职未结束
                Date endDate = rs.getDate("endDate");
                param.put("endDate", (null != endDate && 3 == pdbillstate ? sdf.format(endDate) : "2199-12-31"));

                // ---- 组织与岗位 ----
                // 兼职所属组织编码
                param.put("orgCode", rs.getString("orgCode"));
                // 兼职岗位编码
                param.put("posCode", rs.getString("posCode"));

                // ---- 备注 ----
                // 兼职备注（来自加入兼职单分录）
                param.put("description", rs.getString("description"));
                list.add(param);
            }
            // 将合并后的员工列表写入返回结果
            result.put("data", list);
        } catch (Exception e) {
            // 异常时返回错误信息
            e.printStackTrace();
            result.put("msg", e.getMessage());
            result.put("code", "500");
        }
        return result;
    }

    /**
     * 构建员工兼职信息查询的基础SQL
     * <p>
     *     从员工加入兼职单分录表出发，LEFT JOIN 加入兼职单表获取审批状态，
     *     LEFT JOIN 移除兼职单分录表和移除兼职单表获取结束日期和移除审批状态，
     *     LEFT JOIN 员工基础信息表、岗位表、行政组织表获取基本字段，
     *     LEFT JOIN 岗位任职历史表和员工基础信息表（二次关联）获取当前上级信息。
     *     只查询加入兼职单审批通过（pa.fbillstate=3）的记录。
     * </p>
     *
     * <h3>核心关联逻辑</h3>
     * <ol>
     *     <li>pae → pa：关联加入兼职单，获取审批状态，WHERE条件限定 fbillstate=3（审批通过）</li>
     *     <li>pae → pe：通过 fpersonid 关联员工基础信息表，获取员工编号</li>
     *     <li>pae → pde：通过 fpersonid 关联移除兼职单分录，获取兼职结束日期</li>
     *     <li>pde → pd：关联移除兼职单，获取移除审批状态，用于判断结束日期是否有效</li>
     *     <li>pae → pos：通过 fpositionid 关联岗位表，获取兼职岗位编码</li>
     *     <li>pae → org：通过 fadminorgid 关联行政组织表，获取兼职组织编码</li>
     *     <li>pos → phis：通过 pos.fparentid（上级岗位ID）关联任职历史，取当前有效上级（fpositionenddate >= 2199-12-31）</li>
     *     <li>phis → ppe：关联员工基础信息表（二次），获取上级员工编码</li>
     * </ol>
     *
     * @return 包含完整SELECT语句的StringBuilder（以 WHERE pa.fbillstate=3 结尾，便于后续追加AND条件）
     */
    private static StringBuilder getSql() {
        StringBuilder sql = new StringBuilder();
        // /*dialect*/ 标记用于EAS平台识别SQL方言
        sql.append(" /*dialect*/ select ");

        // ===== SELECT 字段列表 =====
        sql.append(" pae.fid id, ");
        sql.append(" pae.fpersonid personid, ");                    // 员工FID
        sql.append(" pe.fnumber personCode, ");                     // 员工编号
        sql.append(" pae.fbizdate startDate, ");                    // 兼职开始日期
        sql.append(" pos.fnumber posCode, ");                       // 兼职岗位编码
        sql.append(" org.fnumber orgCode, ");                       // 兼职所属组织编码
        // 使用STRING_AGG将同一上级岗位下的多位领导编码合并为逗号分隔字段（Kingbase/PostgreSQL语法）
        sql.append(" (SELECT STRING_AGG(ppe_inner.fnumber, ',' ORDER BY ppe_inner.fnumber) ");
        sql.append("  FROM T_HR_EMPPOSTEXPERIENCEHIS phis_inner ");
        sql.append("  LEFT JOIN t_bd_person ppe_inner ON ppe_inner.fid = phis_inner.fpersonid ");
        sql.append("  WHERE phis_inner.fpositionid = pos.fparentid ");
        sql.append("  AND phis_inner.fpositionenddate >= '2199-12-31 00:00:00') leader, ");
       // sql.append(" ppe.fnumber leader, ");                        // 上级员工编码（通过岗位任职历史关联）
        sql.append(" pae.fdescription description, ");               // 加入兼职单备注
        sql.append(" pde.fdescription description2, ");              // 移除兼职单备注（查询用，未返回给调用方）
        sql.append(" pde.fbizdate endDate, ");                       // 兼职结束日期（来自移除兼职单）
        sql.append(" pd.fbillstate pdbillstate ");                   // 移除兼职单审批状态（3:审批通过）

        // ===== FROM 子句及关联表 =====
        sql.append(" from ");
        sql.append(" T_HR_PluralityAddBizBillEntry pae ");                                                              // 员工加入兼职单分录表（主表）
        sql.append(" left join T_HR_PluralityAddBizBill pa on pae.fbillid = pa.fid ");                                  // 加入兼职单表（获取审批状态）
        sql.append(" left join T_HR_PluralityDelBizBillentry pde on pde.FPERSONID = pae.fpersonid ");                   // 移除兼职单分录表（获取结束日期）
        sql.append(" left join T_HR_PluralityDelBizBill pd on pd.fid = pde.fbillid ");                                   // 移除兼职单表（获取移除审批状态）
        sql.append(" left join t_bd_person pe on pe.fid = pae.fpersonid ");                                           // 员工基础信息表（取员工编号）
        sql.append(" left join t_org_position pos on pos.fid = pae.fpositionid ");                                      // 岗位表（取兼职岗位信息）
        sql.append(" left join t_org_admin org on org.fid = pae.fadminorgid ");                                         // 行政组织表
//        sql.append(" left join T_HR_EMPPOSTEXPERIENCEHIS phis on phis.fpositionid = pos.fparentid ");                   // 岗位任职历史表（通过上级岗位ID关联）
//        sql.append(" and phis.fpositionenddate >= '2199-12-31 00:00:00'");                                              // 只取当前有效的任职记录
//        sql.append(" left join t_bd_person ppe on ppe.fid = phis.fpersonid ");                                          // 上级员工（任职历史中的人员）
        // WHERE 条件：只查加入兼职单审批通过的记录，后续可动态追加 AND 条件
        sql.append(" where pa.fbillstate=3 ");
        return sql;
    }
}
