package com.jwipc.finance.controller.rest;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.collect.Lists;
import com.jwipc.exception.DaoException;
import com.jwipc.finance.dto.*;
import com.jwipc.finance.entity.CompanyInvoicedApply;
import com.jwipc.finance.entity.InvoicedApply;
import com.jwipc.finance.logic.*;
import com.jwipc.finance.model.po.InvoicedApplyItemPO;
import com.jwipc.finance.model.query.CreateInvoicedApplyPageQuery;
import com.jwipc.finance.model.query.InvoicedApplyQuery;
import com.jwipc.log.annotation.AuditLogInter;
import com.jwipc.order.client.PurchaseOrderClient;
import com.jwipc.page.PageView;
import com.jwipc.security.LoginUtil;
import com.jwipc.supplier.clent.dto.SupplierDTO;
import com.jwipc.supplier.client.SupplierClient;
import com.jwipc.sys.client.DigitalSealBusinessDetailClient;
import com.jwipc.sys.entity.DigitalSealBusinessDetail;
import com.jwipc.sys.service.IDigitalSealBusinessDetailService;
import com.jwipc.util.EasyExcelUtils;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Objects;

import static com.jwipc.finance.constant.ModuleConst.MODULE_ROOT;

/**
 * @author shenyang.ou
 * @date 2024/3/5 13:56
 * @desc
 */
@RestController
@RequestMapping(MODULE_ROOT + "/invoiced/apply/rest")
@RequiredArgsConstructor
public class InvoicedApplyRestController {

    private final InvoicedApplyLogic invoicedApplyLogic;
    private final DigitalSealBusinessDetailClient digitalSealBusinessDetailClient;
    private final IDigitalSealBusinessDetailService digitalSealBusinessDetailService;
    private final AccountStatementLogic accountStatementLogic;
    private final PurchaseOrderClient purchaseOrderClient;
    private final AccountStatementDetailLogic accountStatementDetailLogic;
    private final PaymentAdvanceApplyDetailLogic paymentAdvanceApplyDetailLogic;
    private final InvoicedApplyPostResultLogic invoicedApplyPostResultLogic;
    private final SupplierClient supplierClient;
    private final CompanyAccountStatementLogic companyAccountStatementLogic;
    private final CompanyInvoicedApplyLogic costInvoicedApplyLogic;


    /**
     * 查询开票申请单列表
     *
     * @param query 查询条件
     * @return 结果
     */
    @AuditLogInter(value = "首页查询列表", module = "采购/财务到票确认")
    @PostMapping("/list")
    public PageView list(InvoicedApplyQuery query) {
        query.setIsSupplier(LoginUtil.isSupplier()?1:0);
        query.setUserId(LoginUtil.getUserId());

        // 1:暂存 2:待采购确认 3:采购拒绝 4:待推送OA审批 5:OA审批中 6:OA审批不通过 7:待财务确认 8:财务拒绝 9:确认通过
        List<Integer> statusList = Lists.newArrayList();
        if(StringUtils.isNotEmpty(query.getIaStatus())) {
            final String[] statusArray = StringUtils.split(query.getIaStatus(), ",");
            for (String status: statusArray) {
                statusList.add(Integer.parseInt(status));
            }
        }else {
            // 角色类型 1:采购角色 2:财务角色
            if (null != query.getRoleType() && 1 == query.getRoleType()) {
                statusList.add(2);
                statusList.add(4);
                statusList.add(5);
                statusList.add(6);
                statusList.add(7);
                statusList.add(8);
                statusList.add(9);
            }
            if (null != query.getRoleType() && 2 == query.getRoleType()) {
                statusList.add(7);
                statusList.add(9);
            }
        }
        query.setStatusList(statusList);

        return invoicedApplyLogic.selectDataByQuery(query);
    }


    @PostMapping("/writeOff")
    public ResponseEntity writeOff(Long id,String writeOff) {
        invoicedApplyLogic.writeOff(id,writeOff);
        return ResponseEntity.ok(true);
    }


    @PostMapping("/toImg")
    public ResponseEntity toImg(Long iaId) {
        InvoicedApplyDTO invoicedApplyDTO = invoicedApplyLogic.getById(iaId);
        if (StringUtils.isNotEmpty(invoicedApplyDTO.getImgCode())&&invoicedApplyDTO.getImgTime()!=null){
            throw new DaoException("该开票申请单已影像化，不可重复操作");
        }
        invoicedApplyLogic.toImg(iaId);
        invoicedApplyLogic.toAllImg(iaId);
        return ResponseEntity.ok(true);
    }

    @PostMapping("/deleteImg")
    public ResponseEntity deleteImg(Long iaId) {
        InvoicedApplyDTO invoicedApplyDTO = invoicedApplyLogic.getById(iaId);
        if (invoicedApplyDTO.getImgTime()==null){
            throw new DaoException("该开票申请单未影像化，不可删除");
        }
        invoicedApplyLogic.deleteImg(iaId);
        invoicedApplyLogic.deleteAllImg(iaId);
        return ResponseEntity.ok(true);
    }

    /**
     * Dimension
     * @param exportFiled 导出的列信息
     * @param queryStr 查询条件
     */
    @PostMapping("/export")
    public void export(HttpServletResponse response, String exportFiled, String queryStr) throws IOException {
        InvoicedApplyQuery query = JSON.parseObject(queryStr,InvoicedApplyQuery.class);
        query.setIsSupplier(LoginUtil.isSupplier()?1:0);
        query.setUserId(LoginUtil.getUserId());

        // 1:暂存 2:待采购确认 3:采购拒绝 4:待推送OA审批 5:OA审批中 6:OA审批不通过 7:待财务确认 8:财务拒绝 9:确认通过
        List<Integer> statusList = Lists.newArrayList();
        if(StringUtils.isNotEmpty(query.getIaStatus())) {
            final String[] statusArray = StringUtils.split(query.getIaStatus(), ",");
            for (String status: statusArray) {
                statusList.add(Integer.parseInt(status));
            }
        }else {
            // 角色类型 1:采购角色 2:财务角色
            if (null != query.getRoleType() && 1 == query.getRoleType()) {
                statusList.add(2);
                statusList.add(4);
                statusList.add(5);
                statusList.add(6);
                statusList.add(7);
                statusList.add(8);
            }
            if (null != query.getRoleType() && 2 == query.getRoleType()) {
                statusList.add(7);
                statusList.add(9);
            }
        }
        query.setStatusList(statusList);
        // 查询数据列表，直接调用列表的查询，无需特殊改动
        final List<InvoicedApplyDTO> exportData = invoicedApplyLogic.listAll(query);
        //动态导出工具类，只需要修改导出excel名称
        EasyExcelUtils.trendsModelWrite(response,"财务到票确认-" + DateUtil.format(new Date(), DatePattern.NORM_DATE_PATTERN),"sheet", exportData, exportFiled);
    }

    /**
     * 查询开票申请单列表
     *
     * @param query 查询条件
     * @return 结果
     */
    @AuditLogInter(value = "首页查询列表", module = "对账资料交接申请")
    @PostMapping("/sup/list")
    public PageView supList(InvoicedApplyQuery query) {
        query.setIsSupplier(LoginUtil.isSupplier()?1:0);
        if (LoginUtil.isSupplier()) {
            query.setSupplierCode(LoginUtil.getAccount());
        } else {
            query.setUserId(LoginUtil.getUserId());
        }
        // 1:暂存 2:待采购确认 3:采购拒绝 4:待推送OA审批 5:OA审批中 6:OA审批不通过 7:待财务确认 8:财务拒绝
        List<Integer> statusList = Lists.newArrayList();
        statusList.add(1);
        statusList.add(2);
        statusList.add(3);
        statusList.add(4);
        statusList.add(5);
        statusList.add(6);
        statusList.add(7);
        statusList.add(8);
        statusList.add(9);
        query.setStatusList(statusList);
        query.setDelFlg(1);
        return invoicedApplyLogic.selectDataByQuery(query);
    }


    /**
     * 导出
     * @param exportFiled 导出的列信息
     * @param queryStr 查询条件
     */
    @PostMapping("/sup/export")
    public void supExport(HttpServletResponse response, String exportFiled, String queryStr) throws IOException {
        InvoicedApplyQuery query = JSON.parseObject(queryStr, InvoicedApplyQuery.class);
        if (LoginUtil.isSupplier()) {
            query.setSupplierCode(LoginUtil.getAccount());
        } else {
            query.setUserId(LoginUtil.getUserId());
        }
        // 1:暂存 2:待采购确认 3:采购拒绝 4:待推送OA审批 5:OA审批中 6:OA审批不通过 7:待财务确认 8:财务拒绝
        List<Integer> statusList = Lists.newArrayList();
        statusList.add(1);
        statusList.add(2);
        statusList.add(3);
        statusList.add(4);
        statusList.add(5);
        statusList.add(6);
        statusList.add(7);
        statusList.add(8);
        statusList.add(9);
        query.setStatusList(statusList);
        query.setDelFlg(1);
        // 查询数据列表，直接调用列表的查询，无需特殊改动
        final List<InvoicedApplyDTO> exportData = invoicedApplyLogic.listAll(query);
        //动态导出工具类，只需要修改导出excel名称
        EasyExcelUtils.trendsModelWrite(response,"对账开票申请-" + DateUtil.format(new Date(), DatePattern.NORM_DATE_PATTERN),"sheet", exportData, exportFiled);
    }


    /**
     * 暂时存表头
     * fin/invoiced/apply/rest/saveHead
     *
     * @param params 请求参数
     * @return 结果
     */
    @AuditLogInter(value = "编辑保存", module = "对账资料交接申请")
    @PostMapping("/saveHead")
    public ResponseEntity updateHead(@RequestBody InvoicedApplySaveParamDTO params) {
        invoicedApplyLogic.updateHead(params);
        return ResponseEntity.ok(true);
    }

    /**
     * 暂时存表头
     *
     * @param params 请求参数
     * @return 结果
     */
    @PostMapping("/save")
    public ResponseEntity dataSave(@RequestBody InvoicedApplySaveParamDTO params) {
        InvoicedApplyDTO headDto = params.getHeadData();
        CreateInvoicedApplyPageQuery query = new CreateInvoicedApplyPageQuery();
        query.setFactoryCode(headDto.getFactoryCode());
        query.setAsId(headDto.getAccountStatementId());
        List<InvoicedApplyItemPO> inquiryPOS = accountStatementDetailLogic.provideCreateInvoicedApplyPage(null, query);
        invoicedApplyLogic.dataSave(params,inquiryPOS);
        return ResponseEntity.ok(true);
    }

    /**
     * 红冲保存
     *
     * @param params 请求参数
     * @return 结果
     */
    @PostMapping("/redReversalSave")
    public ResponseEntity redReversalSave(@RequestBody InvoicedApplySaveParamDTO params) {
        invoicedApplyLogic.redReversalSave(params);
        return ResponseEntity.ok(true);
    }

    /**
     * 红冲财务确认
     *
     * @param param 参数
     */
    @PostMapping("/redReversalFinanceConfirm")
    public ResponseEntity redReversalFinanceConfirm(@RequestBody RedReversalConfirmParamDTO param) {
        invoicedApplyLogic.redReversalFinanceConfirm(param);
        return ResponseEntity.ok(true);
    }

    /**
     * 开票申请编辑是保存数据
     *
     * @param params 开票申请数据
     * @return 结果
     */
    @PostMapping("/edit")
    public ResponseEntity dataEdit(@RequestBody InvoicedApplySaveParamDTO params) {
        InvoicedApplyDTO headDto = params.getHeadData();
        CreateInvoicedApplyPageQuery query = new CreateInvoicedApplyPageQuery();
        query.setFactoryCode(headDto.getFactoryCode());
        query.setAsId(headDto.getAccountStatementId());
        List<InvoicedApplyItemPO> inquiryPOS = accountStatementDetailLogic.provideCreateInvoicedApplyPage(null, query);
        invoicedApplyLogic.dataEdit(params, inquiryPOS);
        return ResponseEntity.ok(true);
    }

    /**
     * 开票申请提交采购确认
     *
     * @param ids 开票申请ID
     * @return 结果
     */
    @PostMapping("/submit/confirm")
    public ResponseEntity submitConfirm(String ids) {
        invoicedApplyLogic.submitConfirm(ids);
        return ResponseEntity.ok(true);
    }

    /**
     * 采购或财务确认开票申请
     *
     * @param params 开票申请数据
     * @return 结果
     */
    @AuditLogInter(value = "采购或财务确认开票申请", module = "开票申请")
    @PostMapping("/approve/confirm")
    public ResponseEntity purchaseConfirm(@RequestBody InvoicedApplySaveParamDTO params){
        if(params.isOldFlag()){//特殊供应商，走2025-07之前的开票审核逻辑
            invoicedApplyLogic.purchaseConfirmOld(params);
        }else{
            //开票申请时获取对账单数据（分库分表后，加入别的事务查询不会生效，剥离到这里查询传入值）
            if(1 == params.getRoleType() && 1 == params.getApproveStatus()){
                //2025-09-06增加采购审核通过保存时，当实际未付金额大于0，判定对账明细中所有订单行是否有未抵扣的预付款金额逻辑校验
                paymentAdvanceApplyDetailLogic.hasUnappliedPrepaymentBalance(params.getHeadData(),params.getAddAdvances());
            }
            invoicedApplyLogic.purchaseConfirm(params);
        }
        return ResponseEntity.ok(true);
    }

    @PostMapping("/approve/confirmCheck")
    public ResponseEntity confirmCheck(@RequestBody InvoicedApplySaveParamDTO params){
        return ResponseEntity.ok(invoicedApplyLogic.confirmCheck(params));
    }

    @PostMapping("/saleContract/confirm")
    public ResponseEntity saleContractConfirm(@RequestBody InvoicedApplySaveParamDTO params){
        invoicedApplyLogic.saleContractConfirm(params);
        return ResponseEntity.ok(true);
    }

    /**
     * 采购撤销待财务确认状态的开票申请
     *
     * @param iaId 开票申请ID
     * @param revokeReason 撤销原因
     * @return 结果
     */
    @PostMapping("/revoke/fin/confirm")
    public ResponseEntity revokeFinConfirm(Long iaId, String revokeReason,Boolean oldFlag) {
        if(oldFlag){//2025-07之前采购撤销财务确认状态的开票申请
            invoicedApplyLogic.revokeFinConfirmOld(iaId, revokeReason);
        }else{
            invoicedApplyLogic.revokeFinConfirm(iaId, revokeReason);
        }
        return ResponseEntity.ok(true);
    }

    /**
     * 采购修改新的付款到期日
     *
     * @param iaId 开票申请ID
     * @param newPaymentExpireDate 新付款到期日
     * @return 结果
     */
    @PostMapping("/revoke/fin/updateNewDate")
    public ResponseEntity updateNewDate(Long iaId, String newPaymentExpireDate) {
        invoicedApplyLogic.updateNewDate(iaId, newPaymentExpireDate);
        return ResponseEntity.ok(true);
    }

    @PostMapping("/approve/confirmCancel")
    @Transactional(rollbackFor = Exception.class)
    public ResponseEntity financeConfirmCancel(String ids) {
        invoicedApplyLogic.financeConfirmCancel(ids);
        return ResponseEntity.ok(true);
    }

    @PostMapping("/payableSend")
    @Transactional(rollbackFor = Exception.class)
    public ResponseEntity payableSend(String ids) {
        invoicedApplyLogic.payableSend(ids);
        return ResponseEntity.ok(true);
    }

    /**
     * 数据导出
     *
     * @param request 请求体
     * @param response 返回体
     * @param id 开票申请单ID
     */
    @AuditLogInter(value = "导出数据", module = "对账资料交接申请")
    @GetMapping("/data/export")
    public void dataExport(HttpServletRequest request, HttpServletResponse response, Long id) {
        invoicedApplyLogic.dataExport(request,response,id);

    }

    /**
     * 开票申请单删除
     *
     * @param ids 开票申请ID
     * @return 结果
     */
    @PostMapping("/del")
    public ResponseEntity dataDel(String ids) {
        invoicedApplyLogic.dataDel(ids,false);
        return ResponseEntity.ok(true);
    }

    /**
     * 接口返回信息
     *
     * @param msg 描述
     * @return 结果
     */
    private JSONObject returnMessage(String msg) {
        JSONObject error = new JSONObject();
        error.put("code", HttpStatus.INTERNAL_SERVER_ERROR);
        error.put("message", msg);
        return error;
    }

    @GetMapping("/checkApply1")
    public ResponseEntity checkApply1(String accountStatementNo, String type, String accountStatementId) {
        final InvoicedApply invoicedApply = invoicedApplyLogic.findInvoicedApplyByStatementNo(accountStatementNo);
        if (ObjectUtil.isNotNull(invoicedApply)){
            //1、状态是“待财务确认发票”，不允许执行”购销合同签署“、”线下附件盖章附件上传“
            if (invoicedApply.getStatus() == 7){
                throw new DaoException("该对账单为发票待财务确认状态，不可操作");
            }
            if (invoicedApply.getStatus() == 9&& invoicedApply.getPostStatus()!=5){
                throw new DaoException("该对账单为发票已财务已确认状态，不可操作");
            }

        }
        return ResponseEntity.ok(true);
    }

    /**
     * 查询对账单的开票申请单是否已经存在，并且为9（发票已确认状态）
     * @type 1 对账单页面发起电子印章签署操作，2 进行附件删除操作
     * @return
     */
    @GetMapping("/checkApply")
    public void checkApply(String accountStatementNo, String type, String accountStatementId) {
        if (type.equals("2")) {
            AccountStatementDTO accountStatementDTO = accountStatementLogic.getById(Long.parseLong(accountStatementId));
            if (Objects.isNull(accountStatementDTO) || StringUtils.isEmpty(accountStatementDTO.getAccountStatementNo())) {
                throw new DaoException("该账单还未到开票申请环节！");
            }
            accountStatementNo = accountStatementDTO.getAccountStatementNo();
        }

        final InvoicedApply invoicedApply = invoicedApplyLogic.findInvoicedApplyByStatementNo(accountStatementNo);
        String msg = "该对账单为发票已确认状态，不可发起电子印章签署操作!";
        if (type.equals("2")) {
            msg = "该对账单为发票已确认状态，无法进行附件删除操作!";
        }
        if (Objects.nonNull(invoicedApply)) {
            throw new DaoException(msg);
        }
    }

    @GetMapping("/checkDelete")
    public ResponseEntity checkDelete(Long id,String accountStatementId,String businessTypeCode) {
        if (businessTypeCode.equals("account_statement")){
            AccountStatementDTO accountStatementDTO = accountStatementLogic.getById(Long.parseLong(accountStatementId));
            if (ObjectUtil.isNotNull(accountStatementDTO)){
                final InvoicedApply invoicedApply = invoicedApplyLogic.findInvoicedExtApplyByStatementNo(accountStatementDTO.getAccountStatementNo());
                if (ObjectUtil.isNotNull(invoicedApply)) {
                    throw new DaoException("该对账单已经创建开票申请，无法进行附件删除操作!");
                }
            }
        } else if(businessTypeCode.equals("company_account_statement")){
            CompanyAccountStatementDTO companyAccountStatementDTO = companyAccountStatementLogic.getById(Long.parseLong(accountStatementId));
            if (ObjectUtil.isNotNull(companyAccountStatementDTO)){
                CompanyInvoicedApply invoicedApply = costInvoicedApplyLogic.findInvoicedExtApplyByStatementNo(companyAccountStatementDTO.getAccountStatementNo());
                if (ObjectUtil.isNotNull(invoicedApply)) {
                    throw new DaoException("该对账单已经创建开票申请，无法进行附件删除操作!");
                }
            }
        }else {
            DigitalSealBusinessDetail digitalSealBusinessDetail = digitalSealBusinessDetailService.getById(id);
            if (StrUtil.isNotEmpty(digitalSealBusinessDetail.getImageCode())){
                throw new DaoException("该附件已经影像化，无法进行附件删除操作!");
            }
        }


        return ResponseEntity.ok(true);
    }

    /**
     * 设置合同补充状态
     * @param accountStatementNo 对账单
     * @param contractSupplementFlag 是否补录 1-是，0-否
     */
    @RequestMapping("/setContractSupplementStatus")
    public ResponseEntity setContractSupplementStatus( String accountStatementNo,Integer contractSupplementFlag) {
        InvoicedApply invoicedApply = invoicedApplyLogic.findInvoicedApplyByStatementNo(accountStatementNo);
        if (ObjectUtil.isNotNull(invoicedApply)){
            if (invoicedApply.getStatus()==9&&invoicedApply.getPostStatus()==5){
                if(contractSupplementFlag==1){
                    invoicedApplyLogic.updateContractSupplementStatus(invoicedApply.getId(),1);
                }else {
                    if (invoicedApply.getContractSupplementStatus()==2){
                        invoicedApplyLogic.updateContractSupplementStatus(invoicedApply.getId(),1);
                    }
                }
            }
        }
        return ResponseEntity.ok(true);
    }

    @PostMapping("/approve/updatePostStatus")
    public ResponseEntity updatePostStatus(Long iaId, Integer type,String paymentExpireDate) {
        if(Objects.isNull(iaId) || Objects.isNull(type)){
            return ResponseEntity.ok(false);
        }
        invoicedApplyLogic.updatePostStatus(iaId, type);
        //更新付款到期日
        invoicedApplyPostResultLogic.updateNExpireDate(iaId, paymentExpireDate);

        return ResponseEntity.ok(true);
    }


    @PostMapping("/statementInvoicing/check")
    public ResponseEntity statementInvoicingCheck(String accountStatementNo){
        if(Objects.isNull(accountStatementNo)){
            return ResponseEntity.ok(false);
        }
        return ResponseEntity.ok(invoicedApplyLogic.statementInvoicingCheck(accountStatementNo));
    }

    @PostMapping("/statementInvoicing/checkHasNGSignOk")
    public ResponseEntity checkHasNGSignOk(String accountStatementId,String year, String month, String supplierCode) {
        if(Objects.isNull(accountStatementId) || Objects.isNull(supplierCode) || Objects.isNull(year) || Objects.isNull(month)) {
            throw new DaoException("参数不能为空!");
        }
        String reStr = purchaseOrderClient.findMonthNGconfirmOrderList(accountStatementId, year, month, supplierCode);
        if (StringUtils.isNotEmpty(reStr)) {
            throw new DaoException(reStr);
        } else {
            return ResponseEntity.ok(false);
        }
    }

    @GetMapping("/getSupplierInfo")
    public SupplierDTO getSupplierTaxNo(String supplierCode) {
        return supplierClient.getSupplierByCode(supplierCode);
    }

    /**
     * 发票红冲
     * @param params
     * @return
     */
    @PostMapping("/redReversal")
    public ResponseEntity redReversal(@RequestBody InvoicedRedReversalParamDTO params) {
        invoicedApplyLogic.redReversal(params);
        return ResponseEntity.ok(true);
    }
}
