package cn.com.smart.form.service;

import cn.com.smart.bean.SmartResponse;
import cn.com.smart.flow.bean.entity.TFlowForm;
import cn.com.smart.flow.service.FlowFormService;
import cn.com.smart.form.FormConstants;
import cn.com.smart.form.bean.entity.TForm;
import cn.com.smart.form.bean.entity.TFormList;
import cn.com.smart.form.enums.FormListDataScopeType;
import cn.com.smart.form.enums.FormType;
import cn.com.smart.form.enums.SearchPluginType;
import cn.com.smart.form.list.SortingSqlResourceCallback;
import cn.com.smart.report.bean.entity.TReport;
import cn.com.smart.report.bean.entity.TReportButton;
import cn.com.smart.report.bean.entity.TReportCustomCell;
import cn.com.smart.report.bean.entity.TReportField;
import cn.com.smart.report.service.IReportSqlResourceCallback;
import cn.com.smart.report.service.impl.ReportInstanceService;
import cn.com.smart.web.ISmartWeb;
import cn.com.smart.web.bean.LabelValue;
import cn.com.smart.web.bean.RequestPage;
import cn.com.smart.web.bean.UserInfo;
import cn.com.smart.web.constant.enums.BtnAuthType;
import cn.com.smart.web.constant.enums.BtnPropType;
import cn.com.smart.web.helper.HttpRequestHelper;
import cn.com.smart.web.service.OrgService;
import cn.com.smart.web.tag.bean.ALink;
import cn.com.smart.web.tag.bean.CustomBtn;
import cn.com.smart.web.tag.bean.CustomTableCell;
import cn.com.smart.web.tag.bean.DelBtn;
import com.mixsmart.enums.YesNoType;
import com.mixsmart.utils.CollectionUtils;
import com.mixsmart.utils.LoggerUtils;
import com.mixsmart.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.ui.ModelMap;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 乌草坡 2019-09-05
 * @since 1.0
 */
@Component
public class FormListInstanceService {

    private static final Logger logger = LoggerFactory.getLogger(FormListInstanceService.class);

    @Autowired
    private FormListService formListServ;
    @Autowired
    private OrgService orgServ;
    @Autowired
    private ReportInstanceService reportInstServ;
    @Autowired
    private FormService formServ;
    @Autowired
    private FlowFormService flowFormServ;

    private IReportSqlResourceCallback reportSqlResourceCallback;

    public FormListInstanceService(IReportSqlResourceCallback reportSqlResourceCallback) {
        this.reportSqlResourceCallback = reportSqlResourceCallback;
    }

    public FormListInstanceService() {
        this.reportSqlResourceCallback = new SortingSqlResourceCallback();
    }

    /**
     * 处理表单列表视图
     * @param id 表单列表ID
     * @param modelMap ModelMap对象
     * @param page 请求对象
     * @param request HttpServlet请求对象
     */
    public void handleListView(String id, ModelMap modelMap, RequestPage page, HttpServletRequest request) {
        TFormList formList = formListServ.queryAssoc(id);
        if(null == formList || StringUtils.isEmpty(formList.getFormId())) {
            LoggerUtils.error(logger, "表单ID或表单列表对象为空");
            return;
        }
        TReport report = formList.getReport();
        List<TReportField> fields = report.getFields();
        if(CollectionUtils.isEmpty(fields)) {
            throw new IllegalArgumentException("表单列表没有字段信息");
        }
        String uri = HttpRequestHelper.getCurrentUri(request);
        uri += "?id="+ StringUtils.handleNull(id);
        UserInfo userInfo = HttpRequestHelper.getUserInfoFromSession(request);
        modelMap.put("currentUri", uri);
        String sorting = request.getParameter("sorting");
        String sortField = request.getParameter("sortField");
        modelMap.put("sorting", sorting);
        modelMap.put("currentSortField", sortField);

        List<TReportField> searchFields = reportInstServ.getSearchFields(fields);
        Map<String, Object> params = handleParam(formList, userInfo);
        //设置搜索字段
        reportInstServ.handleSearchParam(params, request, searchFields);
        params.put(FormConstants.LIST_FORM_SORTING, sorting);
        params.put(FormConstants.LIST_FORM_SORT_FIELD, sortField);
        SmartResponse<Object> smartResp = reportInstServ.getDatas(report.getSqlResource(), params,
                page.getStartNum(), page.getPageSize(), reportSqlResourceCallback);
        //设置搜索值（用于在列表页面回写搜索的值）
        reportInstServ.getSearchParamValues(request, searchFields);
        //设置链接
        List<ALink> alinks = reportInstServ.getALinks(reportInstServ.getALinkFields(fields));
        CustomBtn exportBtn = reportInstServ.getExportBtn("form/list/export?id="+StringUtils.handleNull(id));
        reportInstServ.setCommonProp(uri, page, modelMap, report, fields, searchFields, smartResp, alinks, exportBtn);
        //处理搜索栏
        buildSearchField(modelMap, searchFields);
        //处理自定义按钮
        handleListBtn(modelMap, report.getButtons(), formList, smartResp, uri);
        //处理自定义单元格
        handleListCell(modelMap, report.getCustomCells());
        if(StringUtils.isNotEmpty(report.getWidth())) {
            String width = report.getWidth();
            try {
                width = width.replaceAll("px|PX", "");
                Integer widthInt = Integer.parseInt(width);
                width = widthInt + "px";
                modelMap.put("isOriginalTable", YesNoType.YES.getIndex());
            } catch (Exception e) {
                width = "100%";
            }
            modelMap.put("tableWidth", width);
        } else {
            modelMap.put("tableWidth", "100%");
        }

    }

    /**
     * 导出表单列表
     * @param id 表单列表ID
     * @param request HttpServlet请求对象
     * @return 返回ResponseEntity对象
     */
    public ResponseEntity<byte[]> export(String id, HttpServletRequest request) {
        TFormList formList = formListServ.queryAssoc(id);
        if(null == formList || StringUtils.isEmpty(formList.getFormId())) {
            LoggerUtils.error(logger, "表单ID或表单列表对象为空");
            return new ResponseEntity<byte[]>(HttpStatus.NOT_FOUND);
        }
        LoggerUtils.debug(logger, "正在表单列表数据,表单列表ID为["+id+"]...");
        UserInfo userInfo = HttpRequestHelper.getUserInfoFromSession(request);
        TReport report = formList.getReport();
        List<TReportField> fields = report.getFields();
        if(CollectionUtils.isEmpty(fields)) {
            LoggerUtils.error(logger, "表单list没有字段信息...");
            throw new IllegalArgumentException("表单list没有字段信息");
        }
        List<TReportField> searchFields =  reportInstServ.getSearchFields(fields);
        Map<String, Object> params = handleParam(formList, userInfo);
        //设置搜索字段
        reportInstServ.handleSearchParam(params, request, searchFields);
        return reportInstServ.startExport(report, params);
    }


    private Map<String, Object> handleParam(TFormList formList, UserInfo userInfo) {
        Map<String, Object> params = new HashMap<String, Object>();
        FormListDataScopeType dataScopeType = FormListDataScopeType.getObj(formList.getDataScope());
        switch (dataScopeType) {
            case PERSONAL:
                params.put(FormListDataScopeType.PERSONAL.getAuthFlag(), userInfo.getId());
                break;
            case DEPT:
                params.put(FormListDataScopeType.DEPT.getAuthFlag(), userInfo.getOrgId());
                break;
            case DEPT_AND_SUB_DEPT:
                List<String> subOrgIds = orgServ.getSubOrgIds(userInfo.getOrgId());
                if(null == subOrgIds) {
                    subOrgIds = new ArrayList<>();
                }
                subOrgIds.add(userInfo.getOrgId());
                String[] subOrgIdArray = new String[subOrgIds.size()];
                subOrgIds.toArray(subOrgIdArray);
                params.put(FormListDataScopeType.DEPT_AND_SUB_DEPT.getAuthFlag(), subOrgIdArray);
                break;
            case AUTH_DEPT:
                params.put(FormListDataScopeType.AUTH_DEPT.getAuthFlag(), userInfo.getOrgIds());
                break;
            default:
                break;
        }
        params.put("formId", formList.getFormId());
        return params;
    }

    /**
     * 创建搜索栏
     * @param modelMap
     * @param searchFields
     */
    private void buildSearchField(ModelMap modelMap, List<TReportField> searchFields) {
        if(CollectionUtils.isEmpty(searchFields)) {
            return;
        }
        StringBuilder searchBuilder = new StringBuilder();
        for(TReportField reportField : searchFields) {
            boolean isHandle = true;
            searchBuilder.append("<div class=\"form-group p-r-10\">");
            searchBuilder.append("<label>").append(reportField.getTitle()).append("：").append("</label>");
            if(StringUtils.isNotEmpty(reportField.getSearchCustomOptions())) {
                List<LabelValue> items = reportField.getLabelValues();
                if(CollectionUtils.isNotEmpty(items)) {
                    searchBuilder.append("<select class=\"form-control select-form-control\" ").append("name=\"").append(reportField.getSearchName()).append("\" ");
                    searchBuilder.append(" value=\"").append(StringUtils.handleNull(reportField.getSearchValue())).append("\" ");
                    searchBuilder.append(" >");
                    searchBuilder.append("<option value=\"\">全部</option>");
                    for(LabelValue lv : items) {
                        String selected = "";
                        if(lv.getValue().equals(reportField.getSearchValue())) {
                            selected = " selected='selected' ";
                        }
                        searchBuilder.append("<option value=\"").append(lv.getValue()).append("\" "+selected+" >").append(lv.getLabel()).append("</option>");
                    }
                    searchBuilder.append("</select>");
                }
            } else if(StringUtils.isNotEmpty(reportField.getSearchPluginType())){
                SearchPluginType pluginType = SearchPluginType.getObj(reportField.getSearchPluginType());
                if(null != pluginType) {

                    switch (pluginType) {
                        case INPUT_PLUGIN_SELECT:
                        case INPUT_PLUGIN_TREE:
                        case INPUT_PLUGIN_AUTO_COMPLETE:
                            searchBuilder.append("<input type=\"text\" name=\"").append(reportField.getSearchName()).append("\" class=\"form-control input-form-control ");
                            searchBuilder.append(pluginType.getValue()).append("\"");
                            searchBuilder.append(" data-uri=\"" + reportField.getSearchPluginUrl() + "\" ");
                            break;
                        case SELECT:
                            searchBuilder.append("<select name=\"").append(reportField.getSearchName()).append("\" class=\"form-control select-form-control ");
                            searchBuilder.append("cnoj-").append(SearchPluginType.SELECT.getValue()).append("\" ");
                            searchBuilder.append(" data-uri=\"" + reportField.getSearchPluginUrl() + "\" data-default-value=\""+StringUtils.handleNull(reportField.getSearchValue())+"\">");
                            searchBuilder.append("<option value=\"\">全部</option>");
                            searchBuilder.append("</select>");
                            break;
                        case INPUT_PLUGIN_DATE:
                        case INPUT_PLUGIN_DATETIME:
                        case INPUT_PLUGIN_TIME:
                            searchBuilder.append("<input type=\"text\" name=\"").append(reportField.getSearchName()).append("\" class=\"form-control input-form-control ");
                            searchBuilder.append(pluginType.getValue()).append("\" ");
                            String format = reportField.getSearchDataFormat();
                            String defaultFormat = "";
                            if (pluginType == SearchPluginType.INPUT_PLUGIN_DATE) {
                                defaultFormat = "yyyy-mm-dd";
                            } else if (pluginType == SearchPluginType.INPUT_PLUGIN_DATETIME) {
                                defaultFormat = "yyyy-mm-dd hh:ii:ss";
                            } else if (pluginType == SearchPluginType.INPUT_PLUGIN_TIME) {
                                defaultFormat = "hh:ii:ss";
                            }
                            if(StringUtils.isNotEmpty(format)) {
                                format = format.replace("MM", "mm");
                                format = format.replace("mi", "ii");
                                format = format.replace("HH", "hh");
                            }
                            format = StringUtils.isEmpty(format) ? defaultFormat : format;
                            searchBuilder.append(" data-date-format=\"").append(format).append("\" ");
                            break;
                        default:
                            break;
                    }
                }
                if(null != pluginType && pluginType != SearchPluginType.SELECT) {
                    searchBuilder.append(" data-is-show-all=\"yes\" data-is-show-none=\"yes\" data-is-search-show-none=\"yes\" ")
                            .append("data-default-value=\"" + StringUtils.handleNull(reportField.getSearchValue()) + "\"")
                            .append(" value=\"" + StringUtils.handleNull(reportField.getSearchValue()) + "\" /> ");
                } else if(pluginType != SearchPluginType.SELECT) {
                    isHandle = false;
                }
            } else {
                isHandle = false;
            }
            if(!isHandle) {
                searchBuilder.append("<input type=\"text\" class=\"form-control input-form-control\" name=\"")
                        .append(reportField.getSearchName()).append("\" placeholder=\"请输入")
                        .append(reportField.getTitle()).append("\" value=\"" + StringUtils.handleNull(reportField.getSearchValue()) + "\" />");
            }
            searchBuilder.append("</div>");
        }
        modelMap.put("searchTemplate", searchBuilder.toString());
    }

    /**
     * 处理列表按钮
     * @param modelMap
     * @param buttons
     * @param formList
     * @param smartResp
     * @param listUrl
     */
    private void handleListBtn(ModelMap modelMap, List<TReportButton> buttons,
                               TFormList formList, SmartResponse<Object> smartResp, String listUrl) {
        if(CollectionUtils.isEmpty(buttons)) {
            return;
        }
        String formId = formList.getFormId();
        String processName = "";
        TForm form = formServ.find(formId).getData();
        if(null != form && FormType.FLOW_FORM.getValue().equals(form.getType())) {
            processName = getProcessName(smartResp, form);
        }
        List<CustomBtn> customBtns = new ArrayList<>(buttons.size());
        DelBtn delBtn = null;
        for(TReportButton button : buttons) {
            String url = button.getUrl();
            if(StringUtils.isNotEmpty(url)) {
                url = url.replace("${formId}", formId);
                url = url.replace("${processName}", processName);
            }
            YesNoType isAuth = YesNoType.getSupportDefaultObj(button.getIsAuth());
            if(BtnAuthType.DELETE.getValue().equals(button.getBtnId())) {
                delBtn = new DelBtn(url, button.getPromptMsg(), listUrl, null, null);
                delBtn.setIsAuth(isAuth.getValue());
                continue;
            }
            CustomBtn customBtn = new CustomBtn(button.getBtnId(),
                    button.getDialogTitle(),
                    button.getName(),
                    url,
                    button.getBtnIcon(),
                    button.getSelectedType(),
                    button.getParamName());
            BtnPropType.OpenStyle openStyle = BtnPropType.OpenStyle.getObj(button.getOpenType());
            if(null != openStyle) {
                customBtn.setOpenStyle(openStyle);
            }
            customBtn.setSort(button.getSortOrder());
            customBtn.setIsAuth(isAuth.getValue());
            customBtn.setBtnStyle(button.getBtnStyle());
            customBtn.setWidth(button.getDialogWidth());
            customBtns.add(customBtn);
        }
        if(null != delBtn) {
            modelMap.put("delBtn", delBtn);
        }
        modelMap.put("customBtns", customBtns);
    }

    /**
     * 获取流程名称；如果有列表数据则从第一个字段获取流程名称；获取失败，则从列表数据中最后一个直为流程名称
     * 如果没有列表数据，则通过表单ID获取流程名称
     * @param smartResp
     * @param form
     * @return
     */
    private String getProcessName(SmartResponse<Object> smartResp, TForm form) {
        String processName = null;
        if(ISmartWeb.OP_SUCCESS.equals(smartResp.getResult())) {
            Object[] array = (Object[]) smartResp.getDatas().get(0);
            String formDataId = StringUtils.handleNull(array[0]);
            Map<String, Object> param = new HashMap<>(1);
            param.put("formDataId", formDataId);
            SmartResponse<TFlowForm> queryResp = flowFormServ.findByParam(param);
            if(ISmartWeb.OP_SUCCESS.equals(queryResp.getResult())) {
                processName = queryResp.getDatas().get(0).getProcessName();
            }
            if(StringUtils.isEmpty(processName)) {
                processName = StringUtils.handleNull(array[array.length - 1]);
            }
        }
        if(StringUtils.isEmpty(processName)) {
            Map<String, Object> param = new HashMap<>(1);
            param.put("formId", form.getId());
            SmartResponse<TFlowForm> queryResp = flowFormServ.findByParam(param);
            if(ISmartWeb.OP_SUCCESS.equals(queryResp.getResult())) {
                processName = queryResp.getDatas().get(0).getProcessName();
            }
        }
        return processName;
    }

    /**
     * 处理列表自定义单元格
     * @param modelMap
     * @param reportCustomCells
     */
    private void handleListCell(ModelMap modelMap, List<TReportCustomCell> reportCustomCells) {
        if(CollectionUtils.isEmpty(reportCustomCells)) {
            return;
        }
        List<CustomTableCell> tableCells = new ArrayList<>(reportCustomCells.size());
        for(TReportCustomCell customCell : reportCustomCells) {
            CustomTableCell tableCell = new CustomTableCell();
            tableCell.setContent(customCell.getContent());
            tableCell.setPosition(customCell.getPosition());
            String paramName = customCell.getParamName();
            if(StringUtils.isNotEmpty(paramName) && StringUtils.isNotEmpty(customCell.getParamValue())) {
                String[] paramNames = paramName.split(ISmartWeb.MULTI_VALUE_SPLIT);
                String[] paramValues = customCell.getParamValue().split(ISmartWeb.MULTI_VALUE_SPLIT);
                Map<String, Object> args = new HashMap<>(paramNames.length);
                int valueSize = paramValues.length;
                for(int i = 0; i < paramNames.length; i++) {
                    if(i > (valueSize - 1)) {
                        args.put(paramNames[i], "");
                    } else {
                        args.put(paramNames[i], paramValues[i]);
                    }
                }
                tableCell.setParamsMap(args);
            }
            tableCells.add(tableCell);
        }
        modelMap.put("customCells", tableCells);
    }
}
