package com.jeeplus.finance.projectRecords.controller;

import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jeeplus.aop.demo.annotation.DemoMode;
import com.jeeplus.common.excel.ExcelOptions;
import com.jeeplus.common.excel.annotation.ExportMode;
import com.jeeplus.common.utils.ResponseUtil;
import com.jeeplus.finance.invoice.util.EasyPoiUtil;
import com.jeeplus.finance.projectRecords.service.CwProjectRecordsService;
import com.jeeplus.finance.projectRecords.service.dto.CwProjectRecordsDTO;
import com.jeeplus.finance.projectRecords.service.dto.CwProjectRecordsImportDTO;
import com.jeeplus.logging.annotation.ApiLog;
import com.jeeplus.logging.constant.enums.LogTypeEnum;
import com.jeeplus.sys.feign.IDictApi;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 财务项目登记controller
 * @author: 徐滕
 * @version: 2022-11-10 14:55
 */
@RestController
@Api("财务项目信息")
@RequestMapping(value = "/cwProjectRecords")
public class CwProjectRecordsController {

    @Resource
    private CwProjectRecordsService cwProjectRecordsService;

    private static Logger log = LoggerFactory.getLogger(CwProjectRecordsController.class);

    /**
     * 查询财务项目信息列表
     * @return
     */
    @ApiLog("查询财务项目信息列表")
    @GetMapping("getCwProjectData")
    public List<String> getCwProjectData(String id) throws Exception {
        List<String> idList = cwProjectRecordsService.findAllList (id);
        return idList;
    }

    /**
     * 查询项目组成员id
     * @return
     */
    @ApiLog("查询项目组成员id")
    @GetMapping("getMembersId")
    public List<String> getMembersId(String id) throws Exception {
        List<String> idList = cwProjectRecordsService.getMembersId(id);
        return idList;
    }

    /**
     * 添加项目组成员
     * @return
     */
    @ApiLog("添加项目组成员")
    @PostMapping("insertMembers")
    public void insertMembers(String projectId,String membersId,String userId) throws Exception {
        cwProjectRecordsService.addMembers(projectId,membersId,userId);
    }

    /**
     * 查询财务项目信息列表
     * @param cwProjectRecordsDTO
     * @param page
     * @return
     */
    @ApiLog("查询财务项目信息列表")
    // @PreAuthorize("hasAuthority('cwProjectRecords:list')")
    @GetMapping("list")
    public ResponseEntity<IPage<CwProjectRecordsDTO>> data(CwProjectRecordsDTO cwProjectRecordsDTO, Page<CwProjectRecordsDTO> page) throws Exception {
        IPage<CwProjectRecordsDTO> result = new Page<CwProjectRecordsDTO>();
        result = cwProjectRecordsService.findList (page,cwProjectRecordsDTO);
        for (CwProjectRecordsDTO record : result.getRecords()) {
            List<String> operatorList = new ArrayList<>();

            // 依次判断三个字段，非空才加入列表
            if (StringUtils.isNotBlank(record.getProjectExecutor())) {
                operatorList.add(record.getProjectExecutor());
            }
            if (StringUtils.isNotBlank(record.getProjectMasterId())) {
                operatorList.add(record.getProjectMasterId());
            }
            if (StringUtils.isNotBlank(record.getProjectLeaderId())) {
                operatorList.add(record.getProjectLeaderId());
            }

            // 用逗号拼接，空列表会自动返回空字符串，完美符合需求
            String projectOperators = String.join(",", operatorList);
            record.setProjectOperators(projectOperators);
        }

        return ResponseEntity.ok (result);
    }

    /**
     * 查询财务项目信息列表(获取有报告的项目及老项目)
     * @param cwProjectRecordsDTO
     * @param page
     * @return
     */
    @ApiLog("查询财务项目信息列表(获取有报告的项目及老项目)")
    // @PreAuthorize("hasAuthority('cwProjectRecords:list')")
    @GetMapping("newList")
    public ResponseEntity<IPage<CwProjectRecordsDTO>> newList(CwProjectRecordsDTO cwProjectRecordsDTO, Page<CwProjectRecordsDTO> page) throws Exception {
        IPage<CwProjectRecordsDTO> result = new Page<CwProjectRecordsDTO>();
        result = cwProjectRecordsService.findNewList (page,cwProjectRecordsDTO);
        return ResponseEntity.ok (result);
    }

    /**
     * 查询有是否预开票的项目
     * @param cwProjectRecordsDTO
     * @param page
     * @return
     */
    @ApiLog("查询有是否预开票的项目")
    // @PreAuthorize("hasAuthority('cwProjectRecords:list')")
    @GetMapping("noReportList")
    public ResponseEntity<IPage<CwProjectRecordsDTO>> noReportList(CwProjectRecordsDTO cwProjectRecordsDTO, Page<CwProjectRecordsDTO> page) throws Exception {
        IPage<CwProjectRecordsDTO> result = new Page<CwProjectRecordsDTO>();
        result = cwProjectRecordsService.findNoReportList (page,cwProjectRecordsDTO);
        return ResponseEntity.ok (result);
    }

    /**
     * 查询预开票项目信息列表
     * @param cwProjectRecordsDTO
     * @param page
     * @return
     */
    @ApiLog("查询预开票项目信息列表")
    // @PreAuthorize("hasAuthority('cwProjectRecords:list')")
    @GetMapping("preInvoiceList")
    public ResponseEntity<IPage<CwProjectRecordsDTO>> preInvoiceList(CwProjectRecordsDTO cwProjectRecordsDTO, Page<CwProjectRecordsDTO> page) throws Exception {
        IPage<CwProjectRecordsDTO> result = new Page<CwProjectRecordsDTO>();
        result = cwProjectRecordsService.findPreInvoiceList (page,cwProjectRecordsDTO);
        return ResponseEntity.ok (result);
    }

    /**
     * 查询财务项目信息列表
     * @param cwProjectRecordsDTO
     * @param page
     * @return
     */
    @ApiLog("查询财务项目信息列表")
    // @PreAuthorize("hasAuthority('cwProjectRecords:list')")
    @GetMapping("getList")
    public ResponseEntity<IPage<CwProjectRecordsDTO>> getList(CwProjectRecordsDTO cwProjectRecordsDTO, Page<CwProjectRecordsDTO> page) throws Exception {
        IPage<CwProjectRecordsDTO> result = new Page<CwProjectRecordsDTO>();
        result = cwProjectRecordsService.getList (page,cwProjectRecordsDTO);
        return ResponseEntity.ok (result);
    }

    /**
     * 查询项目数据集合,和上面list接口是一样的，目的是跳过findList mapper接口的数据规则（比如仅部门可见、仅自己可见之类的）
     */
    @GetMapping("list2")
    public ResponseEntity<IPage<CwProjectRecordsDTO>> data2(CwProjectRecordsDTO cwProjectRecordsDTO, Page<CwProjectRecordsDTO> page) throws Exception {
        IPage<CwProjectRecordsDTO> result = new Page<CwProjectRecordsDTO>();
        result = cwProjectRecordsService.findList2 (page,cwProjectRecordsDTO);
        return ResponseEntity.ok (result);
    }

    /**
     * 查询财务项目详情
     * @param id
     * @return
     */
    @ApiLog("查询财务项目详情")
//    @PreAuthorize ("hasAnyAuthority('cwProjectRecords:view','cwProjectRecords:add','cwProjectRecords:edit')")
    @GetMapping("queryById")
    public ResponseEntity queryById(@RequestParam("id") String id) {
        CwProjectRecordsDTO cwProjectRecordsDTO = cwProjectRecordsService.queryById ( id );
        return ResponseEntity.ok (cwProjectRecordsDTO);
    }

    /**
     * 保存财务项目信息
     * @param cwProjectRecordsDTO
     * @return
     */
    @ApiLog(value = "修改/新增财务项目信息", type = LogTypeEnum.SAVE)
    @PreAuthorize("hasAnyAuthority('cwProjectRecords:add','cwProjectRecords:edit')")
    @PostMapping("save")
    public ResponseEntity save(@Valid @RequestBody CwProjectRecordsDTO cwProjectRecordsDTO) throws Exception {
        cwProjectRecordsService.save(cwProjectRecordsDTO);
        return ResponseEntity.ok ("操作成功");
    }

    /**
     * 保存财务项目信息-流程
     * @param cwProjectRecordsDTO
     * @return
     */
    @ApiLog(value = "保存财务项目信息-流程", type = LogTypeEnum.SAVE)
    @PreAuthorize("hasAnyAuthority('cwProjectRecords:add','cwProjectRecords:edit')")
    @PostMapping("saveForm")
    public ResponseEntity saveForm(@Valid @RequestBody CwProjectRecordsDTO cwProjectRecordsDTO) throws Exception {
        String id = cwProjectRecordsService.saveForm(cwProjectRecordsDTO);
        return ResponseUtil.newInstance().add("businessTable", "cw_project_records").add("businessId", id).ok ("操作成功");
    }

    /**
     * 保存财务项目组成员信息
     * @param cwProjectRecordsDTO
     * @return
     */
    @ApiLog(value = "保存财务项目组成员信息", type = LogTypeEnum.SAVE)
    @PreAuthorize("hasAnyAuthority('cwProjectRecords:add','cwProjectRecords:edit')")
    @PostMapping("updateMembers")
    public ResponseEntity updateMembers(@Valid @RequestBody CwProjectRecordsDTO cwProjectRecordsDTO) {
        return cwProjectRecordsService.updateMembers(cwProjectRecordsDTO);
    }

    /**
     * 删除财务项目信息
     * @param ids
     * @return
     */
    @ApiLog(value = "删除财务项目信息", type = LogTypeEnum.SAVE)
    @PreAuthorize ("hasAuthority('cwProjectRecords:del')")
    @DeleteMapping("delete")
    public ResponseEntity delete(String ids) {
        return cwProjectRecordsService.deleteByIds(ids);
    }

    /**
     * 根据id修改状态值status
     * @param dto
     * @return
     */
    @ApiOperation(value = "根据id修改状态值status")
    @PostMapping(value = "/updateStatusById")
    public ResponseEntity<String> updateStatusById(@RequestBody CwProjectRecordsDTO dto) {
        String s = cwProjectRecordsService.updateStatusById(dto);
        return ResponseEntity.ok(s);
    }

    /**
     * 导出项目数据
     *
     * @param cwProjectRecordsDTO
     * @param page
     * @param response
     * @throws Exception
     */
    @ApiLog(value = "导出项目数据", type = LogTypeEnum.EXPORT)
    @GetMapping("export")
    @PreAuthorize ("hasAuthority('cwProjectRecords:export')")
    @ApiOperation(value = "导出项目数据")
    public void exportFile(CwProjectRecordsDTO cwProjectRecordsDTO, Page <CwProjectRecordsDTO> page, ExcelOptions options, HttpServletResponse response) throws Exception {
        String fileName = options.getFilename();
        String sheetName = options.getSheetName();
        List<CwProjectRecordsDTO> result = new ArrayList<>();
        if ( ExportMode.current.equals ( options.getMode() ) ) {
            result = cwProjectRecordsService.findList (page,cwProjectRecordsDTO).getRecords();
        } else if (ExportMode.selected.equals ( options.getMode() )) {
            result = cwProjectRecordsService.findList (page,cwProjectRecordsDTO).getRecords().stream ( ).filter ( item ->
                    options.getSelectIds ( ).contains ( item.getId ( ) )
            ).collect ( Collectors.toList ( ) );
        } else {
            page.setSize (-1);
            page.setCurrent (0);
            result = cwProjectRecordsService.findList (page,cwProjectRecordsDTO).getRecords();
        }

        if(result.size()>0){
            String cwStatusDatas = SpringUtil.getBean ( IDictApi.class ).getDictListMapByDict ("cw_status");
            Map<String,Object> cwStatusDictValueDTOs = JSON.parseObject(cwStatusDatas, new TypeReference<Map<String,Object>>() {});
            //报备类型
            String filingType = SpringUtil.getBean ( IDictApi.class ).getDictListMapByDict ("cw_work_client_report_type");
            Map<String,Object> filingTypeDictValueDTOs = JSON.parseObject(filingType, new TypeReference<Map<String,Object>>() {});
            //项目分类
            String projectClassification = SpringUtil.getBean ( IDictApi.class ).getDictListMapByDict ("project_classification");
            Map<String,Object> projectClassificationDictValueDTOs = JSON.parseObject(projectClassification, new TypeReference<Map<String,Object>>() {});

            for (CwProjectRecordsDTO info : result) {
                if(StringUtils.isNotBlank(info.getStatus())){
                    for (String key : cwStatusDictValueDTOs.keySet()) {
                        if(info.getStatus().equals(key)){
                            info.setStatus(String.valueOf(cwStatusDictValueDTOs.get(key)));
                            break;
                        }
                    }
                }

                if(StringUtils.isNotBlank(info.getReportType())){
                    for (String key : filingTypeDictValueDTOs.keySet()) {
                        if(info.getReportType().equals(key)){
                            info.setReportType(String.valueOf(filingTypeDictValueDTOs.get(key)));
                            break;
                        }
                    }
                }

                if(StringUtils.isNotBlank(info.getProjectClassification())){
                    for (String key : projectClassificationDictValueDTOs.keySet()) {
                        if(info.getProjectClassification().equals(key)){
                            info.setProjectClassification(String.valueOf(projectClassificationDictValueDTOs.get(key)));
                            break;
                        }
                    }
                }

            }
        }
        /*result.stream().forEach(item -> {
            if (StringUtils.isNotBlank(item.getStatus())){
                item.setStatus(SpringUtil.getBean ( IDictApi.class ).getDictLabel(item.getStatus(),"cw_status",""));
            }
        });*/
        EasyPoiUtil.exportExcel ( result, sheetName,  sheetName, CwProjectRecordsDTO.class, fileName, response );

    }

    /**
     * 根据客户id获取关联的项目信息
     * @param clientId
     * @return
     */
    @ApiOperation(value = "根据客户id获取关联的项目信息")
    @GetMapping(value = "/getByClientId")
    public ResponseEntity<List<CwProjectRecordsDTO>> getByClientId(String clientId, CwProjectRecordsDTO cwProjectRecordsDTO) throws Exception {
        List<CwProjectRecordsDTO> cwProjectRecordsDTOList = cwProjectRecordsService.getByClientId(clientId,cwProjectRecordsDTO);
        return ResponseEntity.ok(cwProjectRecordsDTOList);
    }

    /**
     * 根据合同id获取关联的项目信息
     * @param contractId
     * @return
     */
    @ApiOperation(value = "根据合同id获取关联的项目信息")
    @GetMapping(value = "/getByContractId")
    public ResponseEntity<List<CwProjectRecordsDTO>> getByContractId(String contractId,CwProjectRecordsDTO cwProjectRecordsDTO) throws Exception {
        List<CwProjectRecordsDTO> cwProjectRecordsDTOList = cwProjectRecordsService.getByContractId(contractId,cwProjectRecordsDTO);
        return ResponseEntity.ok(cwProjectRecordsDTOList);
    }

    /**
     * 查询当前登录人创建的项目 以及 所属项目组的项目(当前登录人未被移除项目组)
     * @return
     */
    @ApiOperation(value = "查询当前登录人创建的项目以及所属项目组的项目")
    @GetMapping(value = "/getHaveProjectIds")
    public ResponseEntity<List<String>> getHaveProjectIds() {
        return cwProjectRecordsService.getHaveProjectIds();
    }

    /**
     * 查询当前登录人是否有可能是项目经理（即是否可以被选择为项目经理，也就是注会）
     * @return
     */
    @ApiOperation(value = "查询当前登录人是否有可能是项目经理（即是否可以被选择为项目经理，也就是注会）")
    @GetMapping(value = "/getUserWhereIsCpaById")
    public ResponseEntity<List<String>> getUserWhereIsCpaById() {
        return cwProjectRecordsService.getUserWhereIsCpaById();
    }


    /**
     * 查找该报告及报告对应项目下的开票列表
     */
    @ApiOperation(value = "查询该报告及报告对应项目下的开票列表")
    @GetMapping(value = "/getReportById")
    public ResponseEntity<List<CwProjectRecordsDTO>> getReportById(String id,CwProjectRecordsDTO cwProjectRecordsDTO) throws Exception {
        List<CwProjectRecordsDTO> reportList=  cwProjectRecordsService.getReportById(id,cwProjectRecordsDTO);
        return ResponseEntity.ok(reportList);
    }


    /**
     * 该项目下审计收费不为0的报告信息
     */
    @ApiOperation(value = "该项目下审计收费不为0的报告信息")
    @GetMapping(value = "/getReportByProjectId")
    public ResponseEntity<List<CwProjectRecordsDTO>> getReportByProjectId(String id,String projectId) throws Exception {
        List<CwProjectRecordsDTO> reportList=  cwProjectRecordsService.getReportByProjectId(id,projectId);
        return ResponseEntity.ok(reportList);
    }

    /**
     * 查询项目下是否存在已开票信息
     * @param id
     * @return
     */
    @ApiLog("查询项目下是否存在已开票信息")
//    @PreAuthorize ("hasAnyAuthority('cwProjectRecords:view','cwProjectRecords:add','cwProjectRecords:edit')")
    @GetMapping("getInvoiceTotal")
    public ResponseEntity getInvoiceTotal(@RequestParam("id") String id) {
        CwProjectRecordsDTO cwProjectRecordsDTO = cwProjectRecordsService.getInvoiceTotal ( id );
        return ResponseEntity.ok (cwProjectRecordsDTO);
    }

    /**
     * 查询预开票项目下的报告是否关联完成
     * @return
     */
    @ApiLog("查询预开票项目下的报告是否关联完成")
//    @PreAuthorize ("hasAnyAuthority('cwProjectRecords:view','cwProjectRecords:add','cwProjectRecords:edit')")
    @GetMapping("getCompleteCollection")
    public String getCompleteCollection() {
        List<CwProjectRecordsDTO> list=cwProjectRecordsService.getCompleteCollection ();
        return JSON.toJSONString(list);
    }




    /**
     * 下载项目导入模板
     *
     * @param response
     * @return
     */
    @GetMapping("/importFinance/template")
    @ApiOperation(value = "下载模板")
    public void importFinanceTemplate(HttpServletResponse response, HttpServletRequest request) {
        try {
            InputStream inputStream = this.getClass().getResourceAsStream("/dot/项目批量导入模板.xlsx");
            //强制下载不打开
            response.setContentType("application/force-download");
            OutputStream out = response.getOutputStream();
            //使用URLEncoder来防止文件名乱码或者读取错误
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("project_records_template.xlsx", "UTF-8"));
            int b = 0;
            byte[] buffer = new byte[1000000];
            while (b != -1) {
                b = inputStream.read(buffer);
                if (b != -1) out.write(buffer, 0, b);
            }
            inputStream.close();
            out.close();
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 导入项目数据excel
     *
     * @return
     */
    @DemoMode
    @PostMapping("/importProjectRecords")
    @ApiLog(value = "导入项目数据excel", type = LogTypeEnum.IMPORT)
    public ResponseEntity importProjectRecords(MultipartFile file, HttpServletRequest request) throws IOException {


        List<CwProjectRecordsImportDTO> listA = new ArrayList<>();
        //获取sheet
        listA = EasyPoiUtil.importExcel(file, 1, 1, CwProjectRecordsImportDTO.class);
        //去除excel中的空行
        listA = getExList(listA);
        //导入前检测数据
        String resultA = cwProjectRecordsService.importProjectRecords(listA);
        if(StringUtils.isNotBlank(resultA)){
            //有返回值，说明导入的数据不正确。向用户抛提示
            return ResponseEntity.badRequest().body  (resultA);
        }

        return ResponseEntity.ok("导入成功");
    }

    /**
     * 去除excel中的空行
     * @param list
     * @return
     */
    public ArrayList<CwProjectRecordsImportDTO> getExList(List<CwProjectRecordsImportDTO> list){

        ArrayList<CwProjectRecordsImportDTO> cwProjectRecordsImportDTOS = new ArrayList<>();

        list.stream().forEach(item->{
            if(objectCheckIsNull(item)){
                cwProjectRecordsImportDTOS.add(item);
            }
        });

        //return cwFinanceImportDTOS;
        return cwProjectRecordsImportDTOS;
    }

    public static boolean objectCheckIsNull(Object object) {
        boolean flag = false; //定义返回结果，默认为true

        if (Objects.isNull(object)) {
            flag = false;
        } else {
            Class clazz = (Class) object.getClass(); // 得到类对象
            Field fields[] = clazz.getDeclaredFields(); // 得到所有属性
            for (Field field : fields) {
                if("serialVersionUID".equals(field.getName()) || "BIZ_CODE".equalsIgnoreCase(field.getName())){
                    continue;
                }
                field.setAccessible(true);
                Object fieldValue = null;
                try {
                    fieldValue = field.get(object); //得到属性值
                    Type fieldType = field.getGenericType();//得到属性类型
                    String fieldName = field.getName(); // 得到属性名
                    log.info("属性类型：" + fieldType + ",属性名：" + fieldName + ",属性值：" + fieldValue);
                } catch (IllegalArgumentException e) {
                    log.error(e.getMessage(), e);
                } catch (IllegalAccessException e) {
                    log.error(e.getMessage(), e);
                }
                if (fieldValue != null && fieldValue != "") {  //只要有一个属性值不为null 就返回false 表示对象不为null
                    flag = true;
                    break;
                }
            }
        }

        return flag;
    }



}
