package com.kingdee.customer.salary.handler;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.ui.ModelMap;

import com.kingdee.bos.BOSException;
import com.kingdee.bos.Context;
import com.kingdee.bos.dao.IObjectPK;
import com.kingdee.bos.dao.ormapping.ObjectUuidPK;
import com.kingdee.eas.common.EASBizException;
import com.kingdee.eas.custom.bill.salary.ISalaryBag;
import com.kingdee.eas.custom.bill.salary.SalaryBagEntryCollection;
import com.kingdee.eas.custom.bill.salary.SalaryBagEntryInfo;
import com.kingdee.eas.custom.bill.salary.SalaryBagFactory;
import com.kingdee.eas.custom.bill.salary.SalaryBagInfo;
import com.kingdee.eas.framework.CoreBaseInfo;
import com.kingdee.eas.hr.affair.EmpEnrollBizBillEntryInfo;
import com.kingdee.eas.hr.base.HRBillStateEnum;
import com.kingdee.eas.util.app.DbUtil;
import com.kingdee.jdbc.rowset.IRowSet;
import com.kingdee.shr.base.syssetting.app.io.fileImport.ImportException;
import com.kingdee.shr.base.syssetting.context.SHRContext;
import com.kingdee.shr.base.syssetting.exception.SHRWebException;
import com.kingdee.shr.base.syssetting.exception.ShrWebBizException;
import com.kingdee.shr.base.syssetting.util.MetaDataUtil;
import com.kingdee.shr.base.syssetting.web.handler.EditHandler;
import com.kingdee.shr.base.syssetting.web.json.JSONUtils;
import com.kingdee.shr.compensation.CmpItemInfo;

/**
 * 工资包编辑处理器
 * @author issuser
 *
 */
public class SalaryBag2EditHandler extends EditHandler {

    private static Logger logger =
            Logger.getLogger("com.kingdee.customer.salary.handler.SalaryBagEditHandler");

    /**
     * 生成工资包的数据明细
     * @param request   HTTP请求对象，包含前端传来的工资包信息
     * @param response  HTTP响应对象，用于向前端返回结果
     * @param modelMap  ModelMap对象，用于在请求处理过程中传递数据
     */
    public void createEntryDetailAction(HttpServletRequest request, HttpServletResponse response, ModelMap modelMap) {
        // 从HTTP请求中获取开始日期、结束日期、补发日期、总金额、工资包ID等参数
        String startDateStr = request.getParameter("startDate");
        String endDateStr = request.getParameter("endDate");
        String reissueDateStr = request.getParameter("reissueDate");
        String money = request.getParameter("money");
        String billId = request.getParameter("billId");

        // 获取业务上下文
        Context ctx = SHRContext.getInstance().getContext();
        try {
            // 构建查询SQL语句，用于获取指定工资包ID的相关信息
            String selectSql = "SELECT  b.fid as personId,b.FNAME_l2 as personName,"
                    + " c.FID as cmpItemId ,c.FNAME_l2 as cmpItemName,a.CFPaycurrency,a.CFendDate "
                    + " FROM CT_SAL_SalaryBag a "
                    + " left join t_bd_person b on a.CFPersonID = b.FID "
                    + " left join T_HR_SCmpItem c on a.CFCmpItemID = c.fid "
                    + " where a.fid = '" + billId + "'";
            System.out.println("工资包变更sql=========" + selectSql);
            // 执行查询操作
            IRowSet rs = DbUtil.executeQuery(ctx, selectSql.toString());
            String cmpItemId = null;
            String cmpItemName = null;
            String paycurrency = null;
            Date soureEndDate = null;
            if (rs.next()) {
                // 从查询结果中取出相关信息
                cmpItemId = rs.getString("cmpItemId");
                cmpItemName = rs.getString("cmpItemName");
                paycurrency = rs.getString("CFPaycurrency");
                soureEndDate = rs.getDate("CFendDate");
            }

            // 创建日期格式化对象
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            // 解析前端传来的结束日期和补发日期
            Date endDate = sdf.parse(endDateStr);
            Date reissueDate = sdf.parse(reissueDateStr);

            // 验证结束日期是否早于原始文档的过期日期
            if (soureEndDate.after(endDate)) {
                throw new ImportException("新的过期日期不能早于原始文档的过期日期");
            }

            // 获取月份明细列表，即从开始日期到结束日期之间的所有月份
            List<Date> monthList = getMonthDetail(startDateStr, endDateStr);
            System.out.println("月份=========" + monthList.size());
            // 创建结果列表，用于存储每个月份的工资包明细
            List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
            // 创建总金额对象，并将其转换为BigDecimal类型
            BigDecimal moneyAmount = new BigDecimal(money);

            // 设置保留的小数位数为两位，并根据金额大小选择合适的取整模式
            int scale = 2; // 保留两位小数
            RoundingMode roundingMode = (moneyAmount.compareTo(BigDecimal.ZERO) < 0)
                    ? RoundingMode.HALF_DOWN  // 负数时向下取整
                    : RoundingMode.HALF_UP;   // 正数时四舍五入
            // 计算平均分配到每个月的金额
            BigDecimal avgAmount = moneyAmount.divide(BigDecimal.valueOf(monthList.size()), scale, roundingMode);

            // 初始化已生成额度的金额和补发月应发金额
            BigDecimal remainder = new BigDecimal(0);
            BigDecimal amountPayable = new BigDecimal(0);

            // 遍历每个月份，生成相应的工资包明细
            for (int i = 0; i < monthList.size(); i++) {
                Map<String, Object> entryMap = new HashMap<String, Object>();
                // 获取当前月份
                Date months = monthList.get(i);
                // 将月份信息和其他相关数据放入entryMap中
                entryMap.put("months", months);
                entryMap.put("paycurrency", paycurrency);
                entryMap.put("cmpItemId", cmpItemId);
                entryMap.put("cmpItemName", cmpItemName);

                // 如果不是最后一个月，则将平均金额加到已生成额度的金额中
                if (monthList.size() - i > 1) {
                    remainder = remainder.add(avgAmount);
                } else {
                    // 如果是最后一个月，则计算最后一个月的实际金额
                    avgAmount = moneyAmount.subtract(remainder);
                }

                // 将平均金额放入entryMap中
                entryMap.put("moneys", avgAmount);
                // 获取变更前的金额
                BigDecimal beforeAmount = getBeforeAmount(billId, sdf.format(months));
                // 将变更前的金额放入entryMap中
                entryMap.put("beforeAmount", beforeAmount);

                // 根据当前月份与补发日期的关系，计算应发金额和补发金额
                if (monthList.get(i).equals(reissueDate)) {
                    // 如果当前月份等于补发日期，不应发补发金额，应发金额为平均金额
                    entryMap.put("reissueAmount", 0);
                    entryMap.put("amountPayable", amountPayable.add(avgAmount));
                } else if (monthList.get(i).after(reissueDate)) {
                    // 如果当前月份晚于补发日期，不应发补发金额，应发金额为平均金额
                    entryMap.put("amountPayable", avgAmount);
                    entryMap.put("reissueAmount", 0);
                } else {
                    // 如果当前月份早于补发日期，应发金额为0，补发金额为平均金额减去变更前金额
                    entryMap.put("amountPayable", 0);
                    entryMap.put("reissueAmount", avgAmount.subtract(beforeAmount));
                    // 更新总应发差额
                    amountPayable = amountPayable.add(avgAmount.subtract(beforeAmount));
                }

                // 输出当前月份的工资包明细
                System.out.println("月份result=========" + entryMap);
                // 将entryMap添加到结果列表中
                resultList.add(entryMap);
            }
            // 将结果列表以JSON格式写入HTTP响应中，返回给前端
            JSONUtils.writeJson(response, resultList);
        } catch (BOSException e) {
            // 捕获并打印业务异常信息
            e.printStackTrace();
        } catch (ParseException e) {
            // 捕获并打印日期解析异常信息
            e.printStackTrace();
        } catch (SHRWebException e) {
            // 捕获并打印Web异常信息
            e.printStackTrace();
        } catch (SQLException e) {
            // 捕获并打印SQL异常信息
            e.printStackTrace();
        }
    }

    /**
     * 获取指定工资包ID和月份的变更前金额
     * @param billId  工资包ID
     * @param months  指定月份
     * @return        变更前的金额
     * @throws BOSException  业务异常
     * @throws SQLException  SQL异常
     */
    private BigDecimal getBeforeAmount(String billId, String months) throws BOSException, SQLException {
        // 获取业务上下文
        Context ctx = SHRContext.getInstance().getContext();
        // 初始化变更前的金额为0
        BigDecimal beforeAmount = new BigDecimal(0);
        // 构建查询SQL语句，用于获取指定工资包ID和月份的变更前金额
        String selectSql = "SELECT CFMoneys FROM  CT_SAL_SalaryBagEntry where FBillID = '" + billId + "' and to_char(CFMonths,'yyyy-MM-dd') = '" + months + "'";
        System.out.println("查找变更前金额=========" + selectSql);
        // 执行查询操作
        IRowSet rs = DbUtil.executeQuery(ctx, selectSql.toString());
        if (rs.next()) {
            // 从查询结果中取出变更前的金额
            beforeAmount = rs.getBigDecimal("CFMoneys");
        }
        // 返回变更前的金额
        return beforeAmount;
    }

    /**
     * 根据开始日期和结束日期，生成月份明细列表
     * @param startDateStr 开始日期字符串
     * @param endDateStr   结束日期字符串
     * @return             月份明细列表
     * @throws ParseException 日期解析异常
     */
    private List<Date> getMonthDetail(String startDateStr, String endDateStr) throws ParseException {
        // 创建日期格式化对象，只提取年月信息
        SimpleDateFormat sdfMonth = new SimpleDateFormat("yyyy-MM");
        // 解析开始日期和结束日期
        Date startDate = sdfMonth.parse(startDateStr);
        Date endDate = sdfMonth.parse(endDateStr);
        Date currentDate = startDate;
        // 创建月份列表
        List<Date> monthList = new ArrayList<Date>();
        // 创建Calendar实例，用于月份计算
        Calendar calendar = Calendar.getInstance();
        // 当前日期小于等于结束日期时，继续循环
        while (endDate.after(currentDate) || currentDate.equals(endDate)) {
            // 将当前日期添加到月份列表中
            monthList.add(currentDate);
            // 设置Calendar的时间为当前日期
            calendar.setTime(currentDate);
            // 将Calendar的时间增加一个月
            calendar.add(Calendar.MONTH, 1);
            // 更新当前日期为增加一个月后的日期
            currentDate = calendar.getTime();
        }
        // 返回月份明细列表
        return monthList;
    }
}
