package cn.myapps.runtime.report.controller;

import cn.myapps.base.web.WebUser;
import cn.myapps.common.Environment;
import cn.myapps.common.auth.IUser;
import cn.myapps.common.controller.Resource;
import cn.myapps.common.data.DataPackage;
import cn.myapps.common.data.ParamsTable;
import cn.myapps.common.exception.CommonException;
import cn.myapps.common.model.report.QueryColumnInfo;
import cn.myapps.common.model.report.Report;
import cn.myapps.common.model.report.ReportGroup;
import cn.myapps.common.model.view.AbstractView;
import cn.myapps.designtime.common.service.DesignTimeServiceManager;
import cn.myapps.designtime.form.service.FormDesignTimeService;
import cn.myapps.designtime.report.service.ReportGroupDesignTimeService;
import cn.myapps.designtime.view.service.ViewDesignTimeService;
import cn.myapps.report.engine.ReportEngine;
import cn.myapps.runtime.activity.service.ActivityRunTimeServiceImpl;
import cn.myapps.runtime.common.controller.AbstractRuntimeController;
import cn.myapps.runtime.dynaform.PermissionType;
import cn.myapps.runtime.dynaform.document.ejb.Document;
import cn.myapps.runtime.dynaform.form.ejb.Form;
import cn.myapps.runtime.dynaform.form.ejb.FormField;
import cn.myapps.runtime.dynaform.form.ejb.ValueStoreField;
import cn.myapps.runtime.macro.runner.IRunner;
import cn.myapps.runtime.macro.runner.JavaScriptFactory;
import cn.myapps.runtime.report.service.ReportService;
import cn.myapps.util.StringUtil;
import com.alibaba.fastjson.JSONObject;
import com.bcxin.saas.core.utils.SqlUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import net.sf.jasperreports.engine.JasperCompileManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.util.*;

@Api(tags = "报表模块")
@Controller
@RequestMapping(value = "/api/runtime/report")
public class ReportController extends AbstractRuntimeController {

    @Autowired
    private ReportService process;

    @Autowired
    private ReportGroupDesignTimeService reportGroupDesignTimeService;

    @RequestMapping(value = "/show/{id}")
    @ResponseBody
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "报表id", required = true, paramType = "path", dataType = "string"),
    })
    public String showReport(@PathVariable String id) throws Exception {
        Environment env = Environment.getInstance();

        if (!StringUtil.isBlank(id)) {
            Report report = process.doView(id);
            ReportEngine engine = ReportEngine.getInstance();
            String path = engine.exportHtml(report, getParams(), getUser());
            path = env.getContext(path);
            return "<script>window.location='" + path + "';</script>";
        } else {
            return "请指定报表!";
        }
    }

    /**
     * 报表显示
     *
     * @param id      报表id
     * @param content 请求包体
     * @return
     * @throws Exception
     */
    @ResponseBody
    @RequestMapping(value = "/showjrxml/{id}", method = RequestMethod.POST, produces = "text/html;charset=UTF-8")
    @ResponseStatus(HttpStatus.OK)
    @ApiOperation(value = "报表显示", notes = "报表显示")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "报表id", required = true, paramType = "path", dataType = "string"),
            @ApiImplicitParam(name = "content", value = "请求包体", required = false, paramType = "body", dataType = "string")
    })
    public String showJrxmlReport(@PathVariable String id, @RequestBody(required = false) String content, String docid) throws Exception {
        try {
            if (!StringUtil.isBlank(id)) {
                IUser user = getUser();
                ParamsTable params = getParams(); // 获取并设置参数

                if (!StringUtil.isBlank(content)) {
                    JSONObject jsonObject = JSONObject.parseObject(content);
                    for (Map.Entry<String, Object> entry : jsonObject.entrySet()) {
                        String key = entry.getKey();
                        Object value = entry.getValue();
                        params.setParameter(key, value);
                    }
                }
                String domainId = params.getParameterAsString("domainId");
                if (!StringUtil.isBlank(domainId)) {
                    user.setDomainid(domainId);

                }
                String htmlPath = "";
                ReportEngine engine = ReportEngine.getInstance();
                Report report = process.doView(id);
                String subReportId = report.getSubReportId();
                //判断是否存在子报表
                if (!StringUtil.isBlank(subReportId)) {
                    // 判断是否存在多个子报表
                    if (subReportId.indexOf(",") == -1) {  // 多个子报表id以,分隔
                        Report subReport = process.doView(subReportId);
                        //这里为了设置子报表的数据源，后面主报表要用到
                        getReportPath(subReport, user, params, docid, "html");
                    } else {
                        String[] subReportIds = subReportId.split(",");
                        for (int i = 0; i < subReportIds.length; i++) {
                            Report subReport = process.doView(subReportIds[i]);
                            //这里为了设置子报表的数据源，后面主报表要用到
                            getReportPath(subReport, user, params, docid, "html");
                        }
                    }
                }
                //返回主报表的html路径
                htmlPath = getReportPath(report, user, params, docid, "html");
                return htmlPath;

            } else {
                return "msg:请指定报表!";
            }

        } catch (CommonException irte) {
            irte.printStackTrace();
            return "msg:已知系统异常！" + irte.getExceptionMsg();

        } catch (Exception e) {
            e.printStackTrace();
            return "msg:未知系统异常！ExceptionName:" + e.getClass().getName() + ",ExceptionMsg:" + e.getMessage();
        } finally {

        }

    }

    private String getReportPath(Report report, IUser user, ParamsTable params, String docid, String type) throws Exception {
        String path = "";
        ReportEngine engine = ReportEngine.getInstance();
        String id = report.getId();
        String parentId = params.getParameterAsString("parentid");
        try{
            //sql数据源
            if (report.getDataSourceType().equals(Report.DATASOURCE_TYPE_SQL) && report.getIsPrint() == 0) {
                // 根据报表ID产生报表HTML路径并返回
                if (report.getTemplateType().equals(Report.TYPE_JRXML)) {
                    if (type.equals("html")) {
                        path = process.generateDynamicReportByReportId(id, user, params);
                    } else if (type.equals("excel")) {
                        path = process.generateExcelByReportId(id, user, params);
                    } else if (type.equals("pdf")) {
                        path = process.generatePdfByReportId(id, user, params);
                    }
                } else {
                    report.setDataSourceType("");
                    if (type.equals("html")) {
                        path = engine.exportHtml(report, params, user);
                    } else if (type.equals("excel")) {
                        path = engine.exportExcel(report, params, user);
                    } else if (type.equals("pdf")) {
                        path = engine.exportPdf(report, params, user);
                    }

                }
            }
            //视图数据源
            else if (report.getDataSourceType().equals(Report.DATASOURCE_TYPE_VIEW) && report.getIsPrint() == 0) {
                String viewId = report.getViewId();
                ViewDesignTimeService vProcess = DesignTimeServiceManager.viewDesignTimeService();
                AbstractView view = vProcess.doView(viewId);
                Document searchDocument = null;
                DataPackage<Document> dataPackage = null;
                Collection<Document> data = null;

                if (view.getSearchForm() != null) {
                    searchDocument = view.getSearchForm().createDocument(params, user);
                    for (Map.Entry<String, Object> entry : searchDocument.getItemMap().entrySet()) {
                        String key = entry.getKey();
                        Object value = entry.getValue();
                        if (value != null) {
                            params.setParameter(key, value);
                        }
                    }
                } else {
                    searchDocument = new Document();
                }
                params.setParameter("parentid", parentId);
                params.setParameter("refreshparent", true);
                params.setParameter("isedit", false);
                params.setParameter("lines", Integer.MAX_VALUE);
                params.setParameter("_viewid", viewId);
                if ("TreeView".equalsIgnoreCase(view.getSimpleClassName())
                        /*	||"CalendarView".equalsIgnoreCase(view.getSimpleClassName())*/
                        || "MapView".equalsIgnoreCase(view.getSimpleClassName())) {
                    params.setParameter("lines", Integer.MAX_VALUE);
                }
                //获取视图数据
                dataPackage = view.getViewTypeImpl().getViewDatas(params, user,
                        searchDocument);
                data = dataPackage.getDatas();
//					ViewDesignTimeService viewDesignTimeService = (ViewDesignTimeService) DesignTimeServiceFactory.resolve(ViewDesignTimeService.class);
//					List<Map<String, Object>> resultMap = viewDesignTimeService
//							.manipulationDocumentDatas2ViewDatas(data, view, params,
//									getUser());
                if (type.equals("html")) {
                    path = process.generateDynamicReportByViewDataSource(report, data, params, user);
                } else if (type.equals("excel")) {
                    path = process.generateExcelByViewDataSource(report, data, params, user);
                } else if (type.equals("pdf")) {
                    path = process.generatePdfByViewDataSource(report, data, params, user);
                }
            }
            //自定义数据源
            else if (report.getDataSourceType().equals(Report.DATASOURCE_TYPE_CUSTOM) && report.getIsPrint() == 0) {
                if (type.equals("html")) {
                    path = process.generateDynamicReportByCustomDataSource(report, params, user);
                }
                //存储过程数据源
            } else if (report.getDataSourceType().equals(Report.DATASOURCE_TYPE_PROCEDURE) && report.getIsPrint() == 0) {
                if (type.equals("html")) {
                    path = process.generateDynamicReportByProcedure(report, user, params);
                } else if (type.equals("excel")) {
                    path = process.generateExcelByProcedure(report, user, params);
                } else if (type.equals("pdf")) {
                    path = process.generateExcelByProcedure(report, user, params);
                }
            } else if (report.getIsPrint() == 1) {

                //作为打印模板使用
                path = process.generateDynamicReportByFormDataSource(report, params, user, docid);
            }
        }finally {
            String jrxmlFileRealPath = Environment.getInstance().getRealPath(report.getJrxmlFilePath());
            String jasperFileRealPath = jrxmlFileRealPath.replace(".jrxml", ".jasper");
            try{
                //将jrxml编译为jasper文件
                JasperCompileManager.compileReportToFile(jrxmlFileRealPath, jasperFileRealPath);
            }catch (Exception e){
                e.printStackTrace();
            }

        }
        return path;
    }

    /**
     * 报表导出excel
     *
     * @param id      报表id
     * @param content 请求包体
     * @return
     * @throws Exception
     */
    @ResponseBody
    @RequestMapping(value = "/exportexcel/{id}", method = RequestMethod.POST, produces = "text/html;charset=UTF-8")
    @ResponseStatus(HttpStatus.OK)
    @ApiOperation(value = "报表导出excel", notes = "报表导出excel")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "报表id", required = true, paramType = "path", dataType = "string"),
            @ApiImplicitParam(name = "content", value = "请求包体", required = false, paramType = "body", dataType = "string")
    })
    public void exportExcel(HttpServletResponse response, @PathVariable String id, @RequestBody(required = false) String content) throws Exception {
        try {
            content = SqlUtil.encode(content);
            if (!StringUtil.isBlank(id)) {
                IUser user = getUser();
                ParamsTable params = getParams(); // 获取并设置参数
                String path = "";
                ReportEngine engine = ReportEngine.getInstance();
                Report report = process.doView(id);

                //判断是否存在子报表
                if (!StringUtil.isBlank(report.getSubReportId())) {
                    Report subReport = process.doView(report.getSubReportId());
                    //这里为了设置子报表的数据源，后面主报表要用到
                    getReportPath(subReport, user, params, null, "excel");
                }
                //返回主报表的路径
                path = getReportPath(report, user, params, null, "excel");

                String agent = request.getHeader("USER-AGENT");
                String fileNameExcel = report.getName() + ".xls";
                String encoding = Environment.getInstance().getEncoding();
                if (null != agent && -1 != agent.indexOf("Firefox")) {
                    response.setContentType("application/x-download; charset=" + encoding + "");
                    response.setHeader("Content-Disposition", "attachment;filename=" + new String(fileNameExcel.getBytes("UTF-8"), "iso-8859-1"));
                } else {
                    response.setContentType("application/x-download; charset=" + encoding + "");
                    response.setHeader("Content-Disposition", "attachment;filename=" + new String(fileNameExcel.getBytes("UTF-8"), "iso-8859-1"));
                }
                //
                Environment env = Environment.getInstance();
                String realPath = env.getRealPath(path);
                File file = new File(realPath);
                //文件下载response设置
                new ActivityRunTimeServiceImpl().doFileDownload(file, response.getOutputStream());
            }

        } catch (CommonException irte) {
            irte.printStackTrace();
            //return "msg\":\"已知系统异常！" + irte.getExceptionMsg();

        } catch (Exception e) {
            e.printStackTrace();
            //return "msg\":\"未知系统异常！ExceptionName:" + e.getClass().getName() + ",ExceptionMsg:" + e.getMessage();
        }

    }

    /**
     * 报表导出pdf
     *
     * @param id      报表id
     * @param content 请求包体
     * @return
     * @throws Exception
     */
    @ResponseBody
    @RequestMapping(value = "/exportpdf/{id}", method = RequestMethod.POST, produces = "text/html;charset=UTF-8")
    @ResponseStatus(HttpStatus.OK)
    @ApiOperation(value = "报表导出pdf", notes = "报表导出pdf")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "报表id", required = true, paramType = "path", dataType = "string"),
            @ApiImplicitParam(name = "content", value = "请求包体", required = false, paramType = "body", dataType = "string")
    })
    public void exportPdf(HttpServletResponse response, @PathVariable String id, @RequestBody(required = false) String content, String docid) throws Exception {
        try {
            content = SqlUtil.encode(content);
            if (!StringUtil.isBlank(id)) {
                WebUser user = getUser();
                ParamsTable params = getParams(); // 获取并设置参数
                String parentId = params.getParameterAsString("parentid");
                String path = "";
                ReportEngine engine = ReportEngine.getInstance();
                Report report = process.doView(id);
                //判断是否存在子报表
                if (!StringUtil.isBlank(report.getSubReportId())) {
                    Report subReport = process.doView(report.getSubReportId());
                    //这里为了设置子报表的数据源，后面主报表要用到
                    getReportPath(subReport, user, params, docid, "pdf");
                }
                //返回主报表的路径
                path = getReportPath(report, user, params, docid, "pdf");
                String agent = request.getHeader("USER-AGENT");
                String fileNameExcel = report.getName() + ".pdf";
                String encoding = Environment.getInstance().getEncoding();
                if (null != agent && -1 != agent.indexOf("Firefox")) {
                    response.setContentType("application/x-download; charset=" + encoding + "");
                    response.setHeader("Content-Disposition", "attachment;filename=" + new String(fileNameExcel.getBytes("UTF-8"), "iso-8859-1"));
                } else {
                    response.setContentType("application/x-download; charset=" + encoding + "");
                    response.setHeader("Content-Disposition", "attachment;filename=" + new String(fileNameExcel.getBytes("UTF-8"), "iso-8859-1"));
                }
                //
                Environment env = Environment.getInstance();
                String realPath = env.getRealPath(path);
                File file = new File(realPath);
                //文件下载response设置
                new ActivityRunTimeServiceImpl().doFileDownload(file, response.getOutputStream());
            }

        } catch (CommonException irte) {
            irte.printStackTrace();
            //return "msg\":\"已知系统异常！" + irte.getExceptionMsg();

        } catch (Exception e) {
            e.printStackTrace();
            //return "msg\":\"未知系统异常！ExceptionName:" + e.getClass().getName() + ",ExceptionMsg:" + e.getMessage();
        }

    }

    /**
     * 获取报表的查询表单模板
     *
     * @param applicationId 软件id
     * @param id            报表id
     * @return
     * @throws Exception
     */
    @GetMapping(path = "/{id}/searchformtemplate/{applicationId}")
    @ResponseStatus(HttpStatus.OK)
    @ApiOperation(value = "获取查询表单模板", notes = "获取查询表单模板")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
            @ApiImplicitParam(name = "id", value = "报表id", required = true, paramType = "path", dataType = "string")
    })
    public Resource getSearchFormTemplate(@PathVariable String applicationId,
                                          @PathVariable String id) throws Exception {
        IUser user = getUser();
        ParamsTable params = getParams();
        Form searchForm = null;
        Report report = process.doView(id);
        //当数据源为视图数据源时
        if (report.getDataSourceType().equals(Report.DATASOURCE_TYPE_VIEW)) {
            ViewDesignTimeService vProcess = DesignTimeServiceManager.viewDesignTimeService();
            AbstractView view = vProcess.doView(report.getViewId());
            //使用视图数据的查询表单
            searchForm = view.getSearchForm();
        } else {
            FormDesignTimeService fs = DesignTimeServiceManager.formDesignTimeService();
            //报表中的查询表单id
            searchForm = fs.doView(report.getDataSourceSearchForm());
        }
        IRunner runner = JavaScriptFactory.getInstance(user.getSessionid(), applicationId);
        Document searchDocument = null;
        if (searchForm != null) {
            searchDocument = searchForm.createDocument(params, getUser());
        } else {
            searchDocument = new Document();
        }
        Map<String, Object> map = new HashMap<String, Object>();

        StringBuilder buffer = new StringBuilder();
        StringBuilder template = new StringBuilder();
        Form form = searchDocument.getForm();

        String formId = form == null ? "" : form.getId();

        List<Map<String, Object>> data = new ArrayList<Map<String, Object>>();
        if (form != null) {
            template.append(form.getHtmlTemplate(searchDocument, runner, user));
            buffer.append(template.toString());
            buffer.append("<input type=\"hidden\" id=\"dy_refreshObj\" formid=\"" + formId + "\"");
            buffer.append(" docid=\"" + searchDocument.getId() + "\" userid=\"" + user.getId() + "\"");
            buffer.append(" mapVal=\"");
            for (Iterator<FormField> iter = form.getAllFields().iterator(); iter.hasNext(); ) {
                Object obj = iter.next();
                if (obj instanceof ValueStoreField) {
                    FormField field = (FormField) obj;
                    buffer.append(field.getName() + ";");
                }
            }
            if (buffer.lastIndexOf(";") != -1) {
                buffer.deleteCharAt(buffer.lastIndexOf(";"));
            }
            Collection<FormField> fields = form.getFields();
            for (FormField formField : fields) {
                Map<String, Object> value = formField.toAttributes(searchDocument, runner, getUser(), PermissionType.MODIFY);
                data.add(value);
            }
            buffer.append("\" />");
        }

        map.put("fields", data);
        map.put("document", searchDocument);
        map.put("template", buffer.toString());
        if (form != null && form.getStyle() != null) {
            map.put("style", form.getStyle());
        }
        return success("ok", map);
    }

    /**
     * 获取当前报表册下的报表
     *
     * @param reportGroupId
     * @return
     */
    @GetMapping("/getReportsInGroup")
    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    @ApiOperation(value = "获取当前报表册下的报表", notes = "获取当前报表册下的报表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "reportGroupId", value = "报表册id", required = true, paramType = "path", dataType = "string"),
    })
    public Resource getReportsInGroup(String reportGroupId, String reportIds) {
        JSONObject json = new JSONObject();
        try {
            String[] ids;
            if (!StringUtil.isBlank(reportGroupId)) {
                ReportGroup reportGroup = reportGroupDesignTimeService.doView(reportGroupId);
                ids = reportGroup.getReportIds().split(";");
            } else {
                ids = reportIds.split(";");
            }
            Map<String, Object> map = new HashMap<>();
            for (String id : ids) {
                Report report = process.findById(id);
                map.put(report.getId(), report.getName());
            }
            json.put("data", map);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return success("ok", json);
    }

    /**
     * 获取报表自定义数据源的列信息
     *
     * @param applicationId
     * @return
     * @throws Exception
     */
    @PostMapping("/getCustomColumnsInfos")
    @ResponseBody
    public List<QueryColumnInfo> getCustomColumnsInfos(@RequestBody String scriptString, String applicationId) throws Exception{
        IUser user = getUser();
        ParamsTable params = getParams();
        List<QueryColumnInfo> customColumnsInfos = process.getCustomColumnsInfos(scriptString, null, params, user, applicationId);
        return customColumnsInfos;
    }

}
