package com.jeeplus.business.finance.controller;

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.business.finance.domain.JyFinanceInvoice;
import com.jeeplus.business.finance.service.JyFinanceInvoiceService;
import com.jeeplus.business.finance.service.dto.JyFinanceDTO;
import com.jeeplus.business.finance.service.dto.JyFinanceInvoiceDTO;
import com.jeeplus.business.finance.service.dto.JyFinanceInvoiceDetailDTO;
import com.jeeplus.business.finance.util.EasyPoiUtil;
import com.jeeplus.common.excel.ExcelOptions;
import com.jeeplus.common.excel.annotation.ExportMode;
import com.jeeplus.common.utils.ResponseUtil;

import com.jeeplus.flowable.feign.IFlowableApi;
import com.jeeplus.logging.annotation.ApiLog;
import com.jeeplus.logging.constant.enums.LogTypeEnum;
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.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

//import com.jeeplus.sys.utils.DictUtils;
//import com.jeeplus.sys.utils.SpringContextHolder;

@Api("财务管理-发票")
@RestController
@RequestMapping(value = "/cw_finance/invoice")
public class CwFinanceInvoiceController {

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

    @Resource
    private JyFinanceInvoiceService cwFinanceInvoiceService;

    @Resource
    private IFlowableApi flowTaskService;

    /**
     * 查询发票列表
     * @param cwFinanceInvoiceDTO
     * @param page
     * @return
     * @throws Exception
     */
    @ApiLog("查询发票列表")
    @PreAuthorize("hasAuthority('cw_finance:invoice:list')")
    @GetMapping("list")
    public ResponseEntity<IPage<JyFinanceInvoiceDTO>> data(JyFinanceInvoiceDTO cwFinanceInvoiceDTO, Page<JyFinanceInvoiceDTO> page) throws Exception {
        IPage<JyFinanceInvoiceDTO> result = new Page<JyFinanceInvoiceDTO>();
        result = cwFinanceInvoiceService.findList (page, cwFinanceInvoiceDTO);
        System.out.println("当前时间1："+System.currentTimeMillis());
        result.getRecords().stream().forEach(i -> {
            // 发票申请
            if (StringUtils.isNotBlank(i.getTaskId()) && StringUtils.isNotBlank(i.getStatus())) {
                if ("2".equals(i.getStatus())) { // “审核中”的数据要获取数据审核人
                    i.setAuditUserIds(flowTaskService.getTaskAuditUsers(i.getTaskId()));  // 获取数据审核人
                }
            }
            // 发票作废
            if (StringUtils.isNotBlank(i.getInvalidTaskId()) && StringUtils.isNotBlank(i.getStatus())) {
                if ("6".equals(i.getStatus())) { // “审核中”的数据要获取数据审核人
                    i.setAuditUserIdsInvalid(flowTaskService.getTaskAuditUsers(i.getInvalidTaskId()));  // 获取数据审核人
                }
            }
        });
        System.out.println("当前时间2："+System.currentTimeMillis());
        return ResponseEntity.ok (result);
    }

    /**
     * 查询发票数据
     * @param id
     * @return
     */
    @ApiLog("查询发票数据")
    @PreAuthorize ("hasAnyAuthority('cw_finance:invoice:view','cw_finance:invoice:add','cw_finance:invoice:edit')")
    @GetMapping("queryById")
    public ResponseEntity queryById(@RequestParam("id") String id) {
        JyFinanceInvoiceDTO cwFinanceInvoiceDTO = cwFinanceInvoiceService.queryById ( id );
        return ResponseEntity.ok (cwFinanceInvoiceDTO);
    }

    /**
     * 查询发票号是否存在
     * @param number
     * @return
     */
    @ApiLog("查询发票号是否存在")
    @GetMapping("queryByNumber")
    public ResponseEntity queryByNumber(@RequestParam("number") String number, @RequestParam(value="id", required = false) String id) {
        Boolean bool = cwFinanceInvoiceService.queryByNumber ( number, id );
        return ResponseEntity.ok (bool);
    }

    /**
     * 保存发票数据
     * @param cwFinanceInvoiceDTO
     * @return
     */
    @ApiLog(value = "修改/新增发票数据", type = LogTypeEnum.SAVE)
    @PreAuthorize("hasAnyAuthority('cw_finance:invoice:add','cw_finance:invoice:edit')")
    @PostMapping("save")
    public ResponseEntity save(@Valid @RequestBody JyFinanceInvoiceDTO cwFinanceInvoiceDTO) throws Exception {
        cwFinanceInvoiceService.saveInvoice(cwFinanceInvoiceDTO);
        return ResponseEntity.ok ("操作成功");
    }

    /**
     * 保存发票数据-流程
     * @param cwFinanceInvoiceDTO
     * @return
     */
    @ApiLog(value = "保存发票数据-流程", type = LogTypeEnum.SAVE)
    @PreAuthorize("hasAnyAuthority('cw_finance:invoice:add','cw_finance:invoice:edit')")
    @PostMapping("saveForm")
    public ResponseEntity saveForm(@Valid @RequestBody JyFinanceInvoiceDTO cwFinanceInvoiceDTO) throws Exception {
        JyFinanceInvoice cwFinanceInvoice = cwFinanceInvoiceService.saveForm(cwFinanceInvoiceDTO);
        return ResponseUtil.newInstance().add("businessTable", "jy_finance_invoice")
                .add("businessId", cwFinanceInvoice.getId())
                .add("recordType",cwFinanceInvoice.getRecordType())
                .add("no", cwFinanceInvoice.getNo())
                .ok ("操作成功");
    }

    /**
     * 作废发票数据-流程
     * @param cwFinanceInvoiceDTO
     * @return
     */
    @ApiLog(value = "作废发票数据-流程", type = LogTypeEnum.SAVE)
    @PreAuthorize("hasAnyAuthority('cw_finance:invoice:add','cw_finance:invoice:edit')")
    @PostMapping("saveFormInvalid")
    public ResponseEntity saveFormInvalid(@Valid @RequestBody JyFinanceInvoiceDTO cwFinanceInvoiceDTO) throws Exception {
        String id = cwFinanceInvoiceService.saveFormInvalid(cwFinanceInvoiceDTO);
        return ResponseUtil.newInstance().add("businessTable", "jy_finance_invoice_invalid").add("businessId", id).ok ("操作成功");
    }

    /**
     * 根据发票作废数据的id查询发票id
     * @param id
     * @return
     */
    @GetMapping("queryIdByInvalidId")
    @ApiOperation(value = "查询发票号是否存在")
    public ResponseEntity<JyFinanceDTO> queryIdByInvalidId(@RequestParam String id) {
        String businessId = cwFinanceInvoiceService.queryIdByInvalidId ( id );
        JyFinanceDTO cwFinanceDTO = new JyFinanceDTO();
        cwFinanceDTO.setBusinessId(businessId);
        return ResponseEntity.ok(cwFinanceDTO);
    }

    /**
     * 删除附件类型
     * @param ids
     * @return
     */
    @ApiLog(value = "删除附件类型", type = LogTypeEnum.SAVE)
    @PreAuthorize ("hasAuthority('cw_finance:invoice:del')")
    @DeleteMapping("delete")
    public ResponseEntity delete(String ids) {
        return cwFinanceInvoiceService.deleteByIds(ids);
    }

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

    /**
     * 确认收款
     * @param dto
     * @return
     */
    @ApiOperation(value = "确认收款")
    @PostMapping(value = "/isReceivables")
    public ResponseEntity<String> isReceivables(@RequestBody JyFinanceInvoiceDTO dto) {
        String s = cwFinanceInvoiceService.isReceivables(dto);
        return ResponseEntity.ok(s);
    }

    /**
     * 下载发票明细导入模板
     *
     * @param response
     * @return
     */
    @GetMapping("/importDetail/template")
    @ApiOperation(value = "下载模板")
    public void importFileTemplate(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("finance_invoice_detail_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();
        }
    }

    /**
     * 导入发票明细数据
     *
     * @return
     */
    @DemoMode
    @PostMapping("/importDetail")
    @ApiLog(value = "导入发票明细数据excel", type = LogTypeEnum.IMPORT)
    public ResponseEntity importDetail(MultipartFile file, HttpServletRequest request) throws IOException {

        ArrayList<JyFinanceInvoiceDetailDTO> arrayList = new ArrayList<>();
        HashMap<String,String> hashMap = new HashMap<>();

        List<JyFinanceInvoiceDetailDTO> listA = new ArrayList<>();
        //获取sheet
        listA = EasyPoiUtil.importExcel(file, 0, 1, JyFinanceInvoiceDetailDTO.class);
        //去除excel中的空行
        listA = getExcelList(listA);
        //导入前检测数据
        String resultA = cwFinanceInvoiceService.importDecide(listA, arrayList, hashMap);
        if(StringUtils.isNotBlank(resultA)){
            //有返回值，说明导入的数据不正确。向用户抛提示
            return ResponseEntity.badRequest().body  (resultA);
        }
        //判断文件中是否有重复的发票号
        if(hashMap.size() != listA.size()){
            return ResponseEntity.badRequest().body  ("文件中存在重复的发票号");
        }

        return ResponseEntity.ok(arrayList);
    }

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

        ArrayList<JyFinanceInvoiceDetailDTO> cwFinanceInvoiceDetailDTOS = new ArrayList<>();

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

        return cwFinanceInvoiceDetailDTOS;
    }

    /**
     * 根据项目id查询项目关联发票
     * @param projectId
     * @param cwFinanceInvoiceDTO
     * @return
     * @throws Exception
     */
    @GetMapping("getByIds")
    @ApiOperation(value = "根据项目id查询项目关联发票")
    public ResponseEntity<List<JyFinanceInvoiceDTO>> getByIds(String projectId,JyFinanceInvoiceDTO cwFinanceInvoiceDTO) throws Exception {
        List<JyFinanceInvoiceDTO> cwFinanceDTO = cwFinanceInvoiceService.getByIds(projectId, cwFinanceInvoiceDTO);
        return ResponseEntity.ok(cwFinanceDTO);
    }

    /**
     * 根据合同id查询项目关联发票
     * @param contractId
     * @param cwFinanceInvoiceDTO
     * @return
     * @throws Exception
     */
    @GetMapping("getByContractId")
    @ApiOperation(value = "根据合同id查询项目关联发票")
    public ResponseEntity<List<JyFinanceInvoiceDTO>> getByContractId(String contractId,JyFinanceInvoiceDTO cwFinanceInvoiceDTO) throws Exception {
        List<JyFinanceInvoiceDTO> cwFinanceDTO = cwFinanceInvoiceService.getByContractId(contractId, cwFinanceInvoiceDTO);
        return ResponseEntity.ok(cwFinanceDTO);
    }

    /**
     * 根据客户id查询项目关联发票
     * @param clientId
     * @param cwFinanceInvoiceDTO
     * @return
     * @throws Exception
     */
    @GetMapping("getIdByClientId")
    @ApiOperation(value = "根据客户id查询项目关联发票")
    public ResponseEntity<List<JyFinanceInvoiceDTO>> getIdByClientId(String clientId,JyFinanceInvoiceDTO cwFinanceInvoiceDTO) throws Exception {
        List<JyFinanceInvoiceDTO> cwFinanceDTO = cwFinanceInvoiceService.getIdByClientId(clientId, cwFinanceInvoiceDTO);
        return ResponseEntity.ok(cwFinanceDTO);
    }

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

    }

    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;
    }










}
