package pwc.taxtech.atms.controller;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import pwc.taxtech.atms.common.message.ErrorMessage;
import pwc.taxtech.atms.constant.enums.EnumServiceType;
import pwc.taxtech.atms.dao.OrganizationMapper;
import pwc.taxtech.atms.dao.ProjectMapper;
import pwc.taxtech.atms.dpo.ReportDto;
import pwc.taxtech.atms.dto.*;
import pwc.taxtech.atms.dto.periodReport.PeriodReportDataParam;
import pwc.taxtech.atms.dto.vatdto.*;
import pwc.taxtech.atms.entity.OrganizationExample;
import pwc.taxtech.atms.entity.Project;
import pwc.taxtech.atms.entity.ProjectExample;
import pwc.taxtech.atms.service.impl.DidiFileUploadService;
import pwc.taxtech.atms.service.impl.DistributedIdService;
import pwc.taxtech.atms.service.impl.ReportUploadService;
import pwc.taxtech.atms.vat.dao.EbitSpreadDataMapper;
import pwc.taxtech.atms.vat.dao.PwcReportAttachMapper;
import pwc.taxtech.atms.vat.entity.*;
import pwc.taxtech.atms.vat.service.impl.ReportServiceImpl;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Optional;

@RestController
@RequestMapping(value = "api/v1/Report")
public class ReportController {
    @Autowired
    ReportServiceImpl reportService;
    @Autowired
    ReportUploadService reportUploadService;

    @RequestMapping(value = "export", method = RequestMethod.POST)
    public ResponseEntity getExportFile(@RequestBody ReportExportDto report) {
        return ResponseEntity.ok(reportService.export(report.getReportData(), "~"));
    }

    @RequestMapping(value = "template/{projectId}/{serviceType}/{period}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public OperationResultDto<List<ReportDto>> getTemplate(@PathVariable String projectId, @PathVariable int serviceType, @PathVariable Integer period) {
        return reportService.getReportTemplate(projectId, EnumServiceType.getEnumByCode(serviceType), period);
    }

    @RequestMapping(value = "filterTemplate/{projectId}/{serviceType}/{period}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public OperationResultDto<List<ReportDto>> getFilterTemplate(@PathVariable String projectId, @PathVariable int serviceType, @PathVariable Integer period) {
        return reportService.getFilterReportTemplate(projectId, EnumServiceType.getEnumByCode(serviceType), period);
    }

    @RequestMapping(value = "generateByTotal/{projectId}/{mergeManual}/{period}", method = RequestMethod.POST,
            produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ResponseEntity generateAllData(@PathVariable String projectId, @PathVariable Integer period,
                                          @RequestParam Optional<String> generator, @PathVariable Boolean mergeManual) {
        return ResponseEntity.ok(reportService.generateData(projectId, EnumServiceType.VAT, mergeManual, period, null, generator));
    }

    @RequestMapping(value = "exportReportData/{projectId}/{period}", method = RequestMethod.POST,
            produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ResponseBody
    public void exportReportData(HttpServletResponse response, @RequestBody PeriodReportDataParam param,
                                 @PathVariable(name = "period", required = false) Integer period,
                                 @PathVariable(name = "projectId", required = false) String projectId) {
        OutputStream ouputStream = null;
        try {
            Workbook tWorkbook = reportService.generateReportData(param.getReportIds(), projectId, period);
            response.setContentType("multipart/form-data");
//            response.setHeader("Content-Disposition", "attachment;fileName=" + new String(param.getFileName().getBytes("GB2312"), "ISO-8859-1"));
            ouputStream = response.getOutputStream();
            tWorkbook.write(ouputStream);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (ouputStream != null) {
                    ouputStream.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }

    }

    @RequestMapping(value = "uploadReportData/{projectId}/{period}", method = RequestMethod.POST,
            produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ResponseBody
    public OperationResultDto uploadReportData(@RequestBody PeriodReportDataParam param,
                                               @PathVariable(name = "period", required = false) Integer period,
                                               @PathVariable(name = "projectId", required = false) String projectId) {
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        try {
            Workbook tWorkbook = reportService.generateReportData(param.getReportIds(), projectId, period);
            tWorkbook.write(bout);
            ReportUpload data = new ReportUpload();
            data.setProjectId(projectId);
            data.setPeriod(period);
            reportUploadService.saveData(bout.toByteArray(), data);
            return OperationResultDto.success();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (bout != null) {
                    bout.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
        return OperationResultDto.error(ErrorMessage.SystemError);
    }

    @RequestMapping(value = "getRunningJob/{projectId}/{period}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ResponseBody
    public PeriodJobDto getRunningJob(@PathVariable String projectId, @PathVariable Integer period) {
        PeriodJob job = reportService.getRunningJob(projectId, period);
        if (job != null) {
            return new PeriodJobDto().copyFromPeriodJob(job);
        } else {
            return null;
        }
    }

    @RequestMapping(value = "getJobStatus/{projectId}//{period}/{jobId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ResponseBody
    public PeriodJobDto getJobStatus(@PathVariable String projectId, @PathVariable Integer period, @PathVariable String jobId) {
        return new PeriodJobDto().copyFromPeriodJob(reportService.getJobStatus(projectId, period, jobId));
    }

    @RequestMapping(value = "templateReferences/{period}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public List<CellTemplateReferenceDto> getTemplateReferences(@PathVariable int period) {
        return reportService.getTemplateReferences(period);
    }

    @RequestMapping(value = "reportData/{reportId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public OperationResultDto<ReportDataDto> getReportData(@PathVariable Long reportId, @RequestHeader String from) {
        OperationResultDto resultDto = new OperationResultDto();
        if (reportId == null || reportId == 0L) {
            resultDto.setResult(false);
            return resultDto;
        }
        return reportService.getCellData(reportId, from);
    }


    @RequestMapping(value = "reportEbitData", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public OperationResultDto<ReportDataDto> reportEbitData(@RequestBody RequestParameterDto requestParameterDto) {
        OperationResultDto operationResultDto = new OperationResultDto();
        /*OperationResultDto resultDto = new OperationResultDto();
         *//*  if (requestParameterDto.getProjectId() == null || requestParameterDto.getReportId() == null) {
            resultDto.setResult(false);
            return resultDto;
        }*/
        operationResultDto = reportService.getCellData( requestParameterDto.getOrgId(), requestParameterDto.getPeriod());
        return operationResultDto;
    }

    @Resource
    private ProjectMapper projectMapper;

    private String getProjId(String orgId, Integer tmsPeriod) {
        ProjectExample pExample = new ProjectExample();
        pExample.createCriteria().andOrganizationIdEqualTo(orgId).andYearEqualTo(tmsPeriod / 100);
        List<Project> pList = projectMapper.selectByExample(pExample);
        if (!pList.isEmpty()) {
            return pList.get(0).getId();
        }
        return "";
    }

    @RequestMapping(value = "report/{templateId}/{period}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public OperationResultDto<ReportDto> getReportByTemplate(@PathVariable Long templateId, @PathVariable Integer period, @RequestHeader String from) {
        OperationResultDto resultDto = new OperationResultDto();
        if (templateId == null || templateId == 0L || period == null || period == 0) {
            resultDto.setResult(false);
            resultDto.setResultMsg("templateId or period is invalid");
            return resultDto;
        }
        return reportService.getReportByTemplate(templateId, period, from);
    }


    @RequestMapping(value = "getCellTemplateConfig/{reportTemplateId}/{period}/{rowIndex}/{columnIndex}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public OperationResultDto<PeriodCellTemplateConfig> getCellTemplateConfig(@PathVariable Long reportTemplateId,
                                                                              @PathVariable Integer period,
                                                                              @PathVariable int rowIndex,
                                                                              @PathVariable int columnIndex,
                                                                              @RequestHeader("from") String projectId) {
        return reportService.getCellTemplateConfig(reportTemplateId, period, rowIndex, columnIndex, projectId);
    }

    @RequestMapping(value = "getStdAccountByIndustry/{industryId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public OperationResultDto<List<VatEnterpriseAccount>> getStdAccountByIndustry(@PathVariable String industryId, @RequestHeader String from) {
        String projectId = StringUtils.EMPTY;
        if (StringUtils.isNotBlank(from) && from.split("@").length > 0) {
            projectId = from.split("@")[0];
        }
        return reportService.getStdAccountByIndustry(industryId, projectId);
    }

    @RequestMapping(value = "getCellAccountRange/{reportTemplateId}/{period}/{rowIndex}/{columnIndex}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public OperationResultDto<List<VatEnterpriseAccountResultDto>> getCellAccountRange(@PathVariable Long reportTemplateId, @PathVariable Integer period, @PathVariable int rowIndex, @PathVariable int columnIndex, @RequestHeader String from) {
        String projectId = StringUtils.EMPTY;
        if (StringUtils.isNotBlank(from) && from.split("@").length > 0) {
            projectId = from.split("@")[0];
        }
        return reportService.getCellAccountRange(reportTemplateId, period, rowIndex, columnIndex, projectId);
    }

    @RequestMapping(value = "addCellManualData", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ResponseEntity addCellManualDataSource(@RequestBody ManualDataSourceDto data, @RequestHeader String from) {
        String projectId = StringUtils.EMPTY;
        if (StringUtils.isNotBlank(from) && from.split("@").length > 0) {
            projectId = from.split("@")[0];
        }
        return ResponseEntity.ok(reportService.addCellManualDataSource(data, from));
    }

    @RequestMapping(value = "addDataSource", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public OperationResultDto<String> addDataSource(@RequestBody DataSourceDto datasource) {
        return reportService.addDataSource(datasource);
    }

    @RequestMapping(value = "getAllDataItems/{dataSourceType}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public OperationResultDto<String> getAllDataItems(@PathVariable Integer dataSourceType) {
        return reportService.getAllDataItems(dataSourceType);
    }


    @RequestMapping(value = "addDataSourceItems", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public OperationResultDto addDataSourceItems(@RequestBody DataSourceDto dataSource) {
        return reportService.addDataSourceItems(dataSource);
    }

    @RequestMapping(value = "getDataSourceDetailList/{dataSourceId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public OperationResultDto<String> getDataSourceDetailList(@PathVariable Long dataSourceId) {
        return reportService.getDataSourceDetailList(dataSourceId);
    }

    @RequestMapping(value = "hasManualDataSource/{projectId}/{period}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public Boolean hasManualDataSource(@PathVariable String projectId, @PathVariable Integer period) {
        return reportService.hasManualDataSource(projectId, period);
    }


    @Autowired
    private DidiFileUploadService didiFileUploadService;

    @RequestMapping(value = "doUpload", method = RequestMethod.POST)
    public OperationResultDto doUploadAttach(@RequestParam("fileName") String fileName, MultipartFile file, String remarks, @RequestParam("activeCol") Long activeCol, @RequestParam("activeRow") Long activeRow, @RequestParam("activeTemplateId") String activeTemplateId) {
        FileUpload fileUpload = null;
        OperationResultDto operationResultDto = new OperationResultDto();
        try {
            fileUpload = didiFileUploadService.uploadFile(file, file.getOriginalFilename(), "附件上传");
            operationResultDto.setData(reportService.bindPwcAttach(activeCol, activeRow, activeTemplateId, fileUpload, remarks));
            operationResultDto.setResultMsg("success");
            return operationResultDto;
        } catch (Exception e) {
            e.printStackTrace();
            return operationResultDto.error();
        }
    }

    @RequestMapping("loadAttachList")
    public List<PwcReportAttach> loadAttachList(@RequestBody ReportAttachDto reportAttachDto) {
        return reportService.loadAttachList(reportAttachDto);
    }

    @RequestMapping("deleteAttach")
    public OperationResultDto deleteAttach(Long id) {
        return reportService.deleteAttach(id);
    }

    @Resource
    private PwcReportAttachMapper pwcReportAttachMapper;

    /*   @RequestMapping("downLoadAttach")
       public OperationResultDto downLoadAttach(Long id) {
           OperationResultDto operationResultDto = new OperationResultDto();
           PwcReportAttachExample example = new PwcReportAttachExample();
           PwcReportAttachExample.Criteria criteria = example.createCriteria();
           criteria.andIdEqualTo(id);
           if (didiFileUploadService.queryPage(pwcReportAttachMapper.selectByExample(example).get(0).getFileUrl()) == true) {
               return operationResultDto.success();
           }
           operationResultDto.setResultMsg("附件导出失败");
           return operationResultDto;
       }
   */
    @Resource
    private OrganizationMapper organizationMapper;

    @RequestMapping("getOrgLists")
    public OperationResultDto getOrgLists() {
        OperationResultDto operationResultDto = new OperationResultDto();
        OrganizationExample organizationExample = new OrganizationExample();
        operationResultDto.setData(organizationMapper.selectByExample(organizationExample));
        return operationResultDto;
    }

    /**
     * 获取模板的report,通过reportid可以获取模板数据
     */
    @RequestMapping(value = "getReportByTemplateEbit", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public OperationResultDto<PeriodReportDto> getReportByTemplateEbit(/*@PathVariable String templateId, @PathVariable Integer period, @PathVariable String orgId*/
             RequestParameterDto requestParameterDto) {
        OperationResultDto resultDto = new OperationResultDto();
        if (requestParameterDto.getTemplateId() == null || requestParameterDto.getPeriod() == null || requestParameterDto.getPeriod() == 0) {
            resultDto.setResult(false);
            resultDto.setResultMsg("templateId or period is invalid");
            return resultDto;
        }
        return reportService.getReportByTemplateEbit(Long.parseLong(requestParameterDto.getTemplateId()), requestParameterDto.getPeriod() % 100, getProjId(requestParameterDto.getOrgId(), requestParameterDto.getPeriod()));
    }


  /*  @RequestMapping(value = "saveAndRefresh", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public OperationResultDto saveAndRefresh(*//*@RequestParam(value = "orgId") String orgId,
                                                          @RequestParam(value = "period") Integer period,
                                                          @RequestParam(value = "specialConsiderations", defaultValue = "0") Integer specialConsiderations,
                                                          @RequestParam(value = "ebitRate", defaultValue = "1") String ebitRate,
                                                          @RequestParam(value = "reportId") Long reportId,*//* @RequestBody RequestParameterDto requestParameterDto) {
        OperationResultDto operationResultDto = new OperationResultDto();
        String projId = getProjId(requestParameterDto.getOrgId(), requestParameterDto.getPeriod());
        try {
            operationResultDto.setData(reportService.loadEbitData(requestParameterDto.getOrgId(), requestParameterDto.getPeriod(), requestParameterDto.getSpecialConsiderations(), requestParameterDto.getEbitRate()));
        } catch (Exception e) {
            return operationResultDto.error();
        }
        operationResultDto.setResultMsg("success");
        return operationResultDto;
    }*/

    @RequestMapping("getlxbId")
    public OperationResultDto getlxbId() {
        OperationResultDto operationResultDto = new OperationResultDto();
        try {
            operationResultDto.setData(reportService.getlxbId());
        } catch (Exception e) {
            e.printStackTrace();
            operationResultDto.error(e.getMessage());
        }
        return operationResultDto;
    }
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;
    /**
     * 批量导出利润表
     */
    @RequestMapping("manyExport")
    public ResponseEntity  manyExport(@RequestBody RequestParameterDto requestParameterDto, HttpServletResponse response, HttpServletRequest request) {
        OperationResultDto operationResultDto = new OperationResultDto();
        try {
            //taskExecutor.execute(new EbitBatchExportJob( reportService,requestParameterDto, request, response));
            reportService.manyExport(requestParameterDto, request, response);
        } catch (Exception e) {
            e.printStackTrace();
            operationResultDto.error(e.getMessage());
            return  new ResponseEntity(HttpStatus.NO_CONTENT);
        }
        return new ResponseEntity(HttpStatus.OK);
    }

    @Autowired
    private EbitSpreadDataMapper ebitSpreadDataMapper;
    @Autowired
    protected DistributedIdService idService;

    /**
     */
    @RequestMapping("spreadToDb")
    public OperationResultDto spreadToDb(HttpServletRequest request, Integer period, String orgId) {

        OperationResultDto operationResultDto = new OperationResultDto();
        try {

            reportService.spreadToDb(request, period, orgId);


        } catch (Exception e) {
            e.printStackTrace();
            operationResultDto.error("保存失败");
        }
        return operationResultDto.success();
    }

}