package com.kingdee.eas.custom.perfweb.handler;

import com.kingdee.bos.BOSException;
import com.kingdee.bos.Context;
import com.kingdee.bos.metadata.entity.EntityViewInfo;
import com.kingdee.bos.metadata.entity.FilterInfo;
import com.kingdee.bos.metadata.entity.FilterItemCollection;
import com.kingdee.bos.metadata.entity.FilterItemInfo;
import com.kingdee.bos.metadata.entity.SelectorItemCollection;
import com.kingdee.bos.metadata.entity.SelectorItemInfo;
import com.kingdee.bos.metadata.query.util.CompareType;
import com.kingdee.eas.basedata.org.AdminOrgUnitInfo;
import com.kingdee.eas.custom.perfweb.utils.CenterOrgUtil;
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.perfweb.app.base.evalplan.EvaResultSummaryCollection;
import com.kingdee.shr.perfweb.app.base.evalplan.EvaResultSummaryFactory;
import com.kingdee.shr.perfweb.app.base.evalplan.EvaResultSummaryInfo;
import com.kingdee.shr.perfweb.app.base.evalplan.IEvaResultSummary;
import com.kingdee.shr.perfweb.app.base.evalplan.PerfEvaObjectInfo;
import com.kingdee.shr.perfweb.portal.handler.PerfTeamAssessmentResultListHandler;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.LinkedHashSet;
import java.util.Set;

/**
 * 团队历史穿透过滤：重写 getDefaultFilter（标品团队历史走此方法），参数从 request / custom_params 读取。
 */
public class PerfTeamAssessmentResultListHandlerEx extends PerfTeamAssessmentResultListHandler {

    private static final Logger logger = LoggerFactory.getLogger(PerfTeamAssessmentResultListHandlerEx.class);
    private static final String DRILL_TYPE_GRADE = "GRADE";
    private static final String EMPTY_PERSON_ID = "00000000-0000-0000-0000-000000000000";
    private static final String[] GRADE_ORDER = {"S", "A+", "A", "B", "C"};

    @Override
    protected FilterInfo getDefaultFilter(HttpServletRequest request, HttpServletResponse response)
            throws SHRWebException {
        FilterInfo filter = super.getDefaultFilter(request, response);
        DrillFilterParams drillParams = parseDrillFilterParams(request);
        logger.error("teamHistory getDefaultFilter enter，periodId=" + drillParams.periodId
                + "，centerOrgId=" + drillParams.centerOrgId
                + "，drillType=" + drillParams.drillType
                + "，grade=" + drillParams.grade
                + "，hasDrill=" + drillParams.hasDrillFilter());
        if (!drillParams.hasDrillFilter() || StringUtils.isBlank(drillParams.periodId)) {
            return filter;
        }
        try {
            appendDrillPersonFilter(filter, drillParams);
            logger.error("teamHistory getDefaultFilter applied，personCount=" + drillParams.resolvedPersonCount);
        } catch (BOSException e) {
            logger.error("团队历史穿透过滤失败，msg=" + e.getMessage());
            throw new ShrWebBizException("团队历史穿透过滤失败：" + e.getMessage());
        }
        return filter;
    }

    private void appendDrillPersonFilter(FilterInfo filter, DrillFilterParams drillParams) throws BOSException {
        Context ctx = SHRContext.getInstance().getContext();
        Set<String> personIds = resolveDrillPersonIds(ctx, drillParams);
        drillParams.resolvedPersonCount = personIds.size();

        FilterItemCollection items = filter.getFilterItems();
        int baseSize = items.size();
        if (personIds.isEmpty()) {
            items.add(new FilterItemInfo("person.id", EMPTY_PERSON_ID, CompareType.EQUALS));
        } else {
            items.add(new FilterItemInfo("person.id", personIds, CompareType.INCLUDE));
        }

        StringBuilder mask = new StringBuilder(StringUtils.defaultString(filter.getMaskString()));
        for (int i = baseSize; i < items.size(); i++) {
            mask.append(" AND #").append(i);
        }
        filter.setMaskString(mask.toString());
    }

    private Set<String> resolveDrillPersonIds(Context ctx, DrillFilterParams params) throws BOSException {
        AdminOrgUnitInfo centerOrg = StringUtils.isNotBlank(params.centerOrgId)
                ? CenterOrgUtil.loadOrg(ctx, params.centerOrgId) : null;

        IEvaResultSummary iEvaResultSummary = EvaResultSummaryFactory.getLocalInstance(ctx);
        FilterInfo filter = new FilterInfo();
        filter.getFilterItems().add(new FilterItemInfo("period.id", params.periodId, CompareType.EQUALS));

        SelectorItemCollection selector = new SelectorItemCollection();
        selector.add(new SelectorItemInfo("person.id"));
        selector.add(new SelectorItemInfo("evaObj.*"));
        selector.add(new SelectorItemInfo("evaObj.adminOrgUnit.*"));
        selector.add(new SelectorItemInfo("auditGradeLevel"));
        selector.add(new SelectorItemInfo("reviseGradeLevel"));
        selector.add(new SelectorItemInfo("gradeLevel"));

        EntityViewInfo evi = new EntityViewInfo();
        evi.setFilter(filter);
        evi.setSelector(selector);
        EvaResultSummaryCollection coll = iEvaResultSummary.getEvaResultSummaryCollection(evi);

        Set<String> personIds = new LinkedHashSet<>();
        if (coll == null) {
            return personIds;
        }
        for (int i = 0; i < coll.size(); i++) {
            EvaResultSummaryInfo info = coll.get(i);
            if (!matchCenterOrg(ctx, info, centerOrg)) {
                continue;
            }
            if (isGradeDrill(params)) {
                String drillGrade = normalizeGrade(params.grade);
                String rowGrade = resolveGradeLevel(info);
                if (StringUtils.isBlank(drillGrade) || !drillGrade.equalsIgnoreCase(rowGrade)) {
                    continue;
                }
            }
            if (info.getPerson() != null && info.getPerson().getId() != null) {
                personIds.add(info.getPerson().getId().toString());
            }
        }
        return personIds;
    }

    private boolean matchCenterOrg(Context ctx, EvaResultSummaryInfo info, AdminOrgUnitInfo centerOrg)
            throws BOSException {
        if (centerOrg == null) {
            return true;
        }
        PerfEvaObjectInfo evaObj = info.getEvaObj();
        if (evaObj == null || evaObj.getAdminOrgUnit() == null) {
            return false;
        }
        return CenterOrgUtil.isUnderCenterOrg(ctx, evaObj.getAdminOrgUnit(), centerOrg);
    }

    private DrillFilterParams parseDrillFilterParams(HttpServletRequest request) throws SHRWebException {
        DrillFilterParams params = new DrillFilterParams();
        params.periodId = firstNonBlank(
                getRequestParam(request, "periodId"),
                getRequestParam(request, "period"));
        params.centerOrgId = firstNonBlank(
                getRequestParam(request, "centerOrgId"),
                getRequestParam(request, "orgId"),
                getRequestParam(request, "adminOrg"));
        params.drillType = getRequestParam(request, "drillType");
        params.grade = normalizeGrade(decodeGradeParam(getRequestParam(request, "grade")));
        return params;
    }

    private String getRequestParam(HttpServletRequest request, String key) throws SHRWebException {
        Object value = getRequestParameter(request, key);
        if (value == null) {
            return null;
        }
        String text = String.valueOf(value).trim();
        return text.isEmpty() ? null : text;
    }

    private boolean isGradeDrill(DrillFilterParams params) {
        return DRILL_TYPE_GRADE.equalsIgnoreCase(params.drillType) && StringUtils.isNotBlank(params.grade);
    }

    private String resolveGradeLevel(EvaResultSummaryInfo info) {
        if (info == null) {
            return "";
        }
        if (StringUtils.isNotBlank(info.getAuditGradeLevel())) {
            return normalizeGrade(info.getAuditGradeLevel());
        }
        if (StringUtils.isNotBlank(info.getReviseGradeLevel())) {
            return normalizeGrade(info.getReviseGradeLevel());
        }
        return normalizeGrade(info.getGradeLevel());
    }

    private String normalizeGrade(String grade) {
        if (StringUtils.isBlank(grade)) {
            return "";
        }
        String trimmed = grade.trim();
        // 穿透标题可能带「A+ (实现)」等后缀，只取等级部分
        int paren = trimmed.indexOf('(');
        if (paren > 0) {
            trimmed = trimmed.substring(0, paren).trim();
        }
        int fullWidthParen = trimmed.indexOf('（');
        if (fullWidthParen > 0) {
            trimmed = trimmed.substring(0, fullWidthParen).trim();
        }
        // URL 误把 A+ 解成 "A " 或 "A"
        if ("A".equals(trimmed) || "A ".equals(trimmed)) {
            return "A+";
        }
        if ("A＋".equals(trimmed) || "A+".equalsIgnoreCase(trimmed)) {
            return "A+";
        }
        for (String item : GRADE_ORDER) {
            if (item.equalsIgnoreCase(trimmed)) {
                return item;
            }
        }
        return trimmed;
    }

    private String firstNonBlank(String... values) {
        if (values == null) {
            return null;
        }
        for (String value : values) {
            if (StringUtils.isNotBlank(value)) {
                return value.trim();
            }
        }
        return null;
    }

    private String decodeGradeParam(String value) {
        if (StringUtils.isBlank(value)) {
            return null;
        }
        try {
            // URL 表单编码会把 + 解码为空格，A+ 须先保护再 decode
            String safe = value.trim().replace("+", "%2B");
            return URLDecoder.decode(safe, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            return value.trim();
        }
    }

    private String decodeParam(String value) {
        if (StringUtils.isBlank(value)) {
            return null;
        }
        try {
            return URLDecoder.decode(value.trim(), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            return value.trim();
        }
    }

    private static final class DrillFilterParams {
        private String periodId;
        private String centerOrgId;
        private String drillType;
        private String grade;
        private int resolvedPersonCount;

        private boolean hasDrillFilter() {
            return StringUtils.isNotBlank(periodId)
                    || StringUtils.isNotBlank(centerOrgId)
                    || (DRILL_TYPE_GRADE.equalsIgnoreCase(drillType) && StringUtils.isNotBlank(grade));
        }
    }
}
