package com.ruoyi.web.work.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanValidators;
import com.ruoyi.web.work.domain.*;
import com.ruoyi.web.work.domain.dto.GenerateDto;
import com.ruoyi.web.work.domain.dto.RejectDto;
import com.ruoyi.web.work.domain.dto.StatementDto;
import com.ruoyi.web.work.domain.dto.StatementExportDto;
import com.ruoyi.web.work.domain.vo.StatementExportListVo;
import com.ruoyi.web.work.mapper.StatementDetailMapper;
import com.ruoyi.web.work.mapper.StatementMapper;
import com.ruoyi.web.work.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.Validator;
import java.math.BigDecimal;
import java.rmi.ServerException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author lsw
 * @date 2024-04-20
 */
@Service
public class StatementServiceImpl extends ServiceImpl<StatementMapper, Statement> implements IStatementService {
    @Autowired
    private StatementMapper statementMapper;

    @Autowired
    private StatementDetailMapper statementDetailMapper;

    @Autowired
    private IStatementDetailService detailService;

    @Autowired
    private ICompanyService companyService;

    @Autowired
    protected Validator validator;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private ICommonService commonService;

    @Autowired
    private IRecordService recordService;

    @Autowired
    private IProjectService projectService;

    @Autowired
    private IPackagesService packagesService;

    @Override
    public List<Statement> selectList(Statement statement) {
        return statementMapper.selectList(statement);
    }

    @Override
    public List<Statement> selectPayList(Statement statement) {
        return statementMapper.selectPayList(statement);
    }

    @Override
    public List<StatementExportListVo> exportList(StatementExportDto dto) {
        List<StatementExportListVo> list = statementMapper.exportList(dto);
        for (int i = 0; i < list.size(); i++) {
            StatementExportListVo e = list.get(i);
            e.setIndex(i + 1);
            e.setFlag(e.getBankName().contains("建行") || e.getBankName().contains("建设银行") ? 0 : 1);
            e.setRemarks(dto.getRemarks());
        }
        return list;
    }

    @Transactional
    @Override
    public AjaxResult makeAdd(List<StatementDetail> list, Statement statement) {
        if (StringUtils.isNull(list) || list.size() == 0) {
            throw new ServiceException("上传结算单数据不能为空！");
        }
        Platform platform = redisCache.getCacheObject(CacheConstants.APP_PLATFORM);
        statement.setUserId(SecurityUtils.getLoginUser().getUser().getUserId());
        statement.setCompanyId(SecurityUtils.getLoginUser().getUser().getCompanyId());
        statement.setOpBy(SecurityUtils.getLoginUser().getUser().getNickName());
        statement.setState(0);
        statement.setGive(0);
        statement.setAudit(0);
        statement.setMoney(BigDecimal.ZERO);
        statement.setServiceCompany(platform.getServiceCompany());
        statement.setFileName(statement.getFile().getOriginalFilename());
        if (!save(statement)) {
            throw new ServiceException("创建结算单失败,请联系平台");
        }
        int successNum = 0;
        for (StatementDetail detail : list) {
            BeanValidators.validateWithException(validator, detail);
            detail.setBankAccount(detail.getBankAccount().trim());
            detail.setStatementId(statement.getId());
            detail.setProjectId(statement.getProjectId());
            detail.setState(0);
            detail.setCompanyId(statement.getCompanyId());
            detail.setNum(StringUtils.generateNumber());
            detail.setServiceMoney(platform.getRate().divide(new BigDecimal("100")).multiply(detail.getMoney()));
            detail.setRealMoney(detail.getMoney().add(detail.getServiceMoney()));
            if (!detailService.save(detail)) {
                throw new ServiceException("导入失败,请联系平台");
            }
            successNum++;
        }
        return AjaxResult.success("创建成功！本次导入" + successNum + " 条数据");
    }

    @Override
    public AjaxResult makeGenerate(Long id) {
        Statement statement = getById(id);
        if (statement == null || !statement.getCompanyId().equals(SecurityUtils.getLoginUser().getUser().getCompanyId())) {
            return AjaxResult.error("结算单不存在或非法操作");
        }
        if (statement.getState() != 0) {
            return AjaxResult.error("不可操作");
        }
        List<StatementDetail> detailList = detailService.selectList(new StatementDetail().setStatementId(statement.getId()));
        if (detailList.isEmpty() || detailList.size() == 0) {
            return AjaxResult.error("结算单发放人数为空");
        }
        detailList.forEach(e -> BeanValidators.makeGenerateValidation(validator, e));
        statement.setState(1);
        statement.setNum(StringUtils.generateNumber());
        statement.setGenerateTime(new Date());
        if (!updateById(statement)) {
            throw new ServiceException("生成结算单失败,请联系平台");
        }
        return AjaxResult.success();
    }

    @Transactional
    @Override
    public AjaxResult makeGenerateByProject(GenerateDto dto) {
        Project project = projectService.getById(dto.getId());
        if (project == null || !project.getCompanyId().equals(SecurityUtils.getLoginUser().getUser().getCompanyId())) {
            return AjaxResult.error("项目不存在或非法操作");
        }
        if (project.getState() == 1) {
            return AjaxResult.error("项目已停用");
        }
        Packages packages = new Packages();
        packages.setProjectId(project.getId());
        packages.setCompanyId(SecurityUtils.getLoginUser().getUser().getCompanyId());
        List<Packages> packagesList = packagesService.selectList(packages);
        if (packagesList.isEmpty() || packagesList.size() == 0) {
            return AjaxResult.error("该项目暂无人接包，无法生成结算单");
        }
        packagesList.forEach(e -> {
            if (e.getAudit() != 2) {
                throw new ServiceException("接包凭证未审核或者审核不通过,请全部审核通过后再生成");
            }
        });
        Platform platform = redisCache.getCacheObject(CacheConstants.APP_PLATFORM);
        Statement statement = new Statement();
        statement.setFileName("自动生成");
        statement.setBatchName(dto.getBatchName());
        statement.setProjectId(project.getId());
        statement.setChannel("银行卡转账");
        statement.setInvoice("增值税全额发票");
        statement.setUserId(SecurityUtils.getLoginUser().getUser().getUserId());
        statement.setCompanyId(SecurityUtils.getLoginUser().getUser().getCompanyId());
        statement.setOpBy(SecurityUtils.getLoginUser().getUser().getNickName());
        statement.setState(0);
        statement.setGive(0);
        statement.setAudit(0);
        statement.setMoney(BigDecimal.ZERO);
        statement.setServiceCompany(platform.getServiceCompany());
        if (!save(statement)) {
            throw new ServiceException("创建结算单失败,请联系平台");
        }
        List<StatementDetail> list = new ArrayList<>();
        packagesList.forEach(e -> {
            StatementDetail detail = new StatementDetail();
            detail.setName(e.getName());
            detail.setIdCard(e.getIdCard());
            detail.setBankName(e.getBankName());
            detail.setAlipay(e.getAlipay());
            detail.setPhone(e.getPhone());
            detail.setBankAccount(e.getBankAccount());
            detail.setStatementId(statement.getId());
            detail.setProjectId(project.getId());
            detail.setState(0);
            detail.setCompanyId(statement.getCompanyId());
            detail.setNum(StringUtils.generateNumber());
            list.add(detail);
        });
        if (!detailService.saveBatch(list)) {
            throw new ServiceException("生成结算单失败,请联系平台");
        }
        return AjaxResult.success();
    }

    @Override
    public AjaxResult makeStatementDetailEdit(StatementDetail detail) {
        if (detail == null || !detail.getCompanyId().equals(SecurityUtils.getLoginUser().getUser().getCompanyId())) {
            return AjaxResult.error("关联结算单明细不存在或非法操作");
        }
        Platform platform = redisCache.getCacheObject(CacheConstants.APP_PLATFORM);
        detail.setServiceMoney(platform.getRate().divide(new BigDecimal("100")).multiply(detail.getMoney()));
        detail.setRealMoney(detail.getMoney().add(detail.getServiceMoney()));
        if (!detailService.updateById(detail)) {
            throw new ServiceException("编辑结算单明细失败");
        }
        return AjaxResult.success();
    }

    @Override
    public AjaxResult manageSubmit(Long id) {
        Statement statement = getById(id);
        if (statement == null || !statement.getCompanyId().equals(SecurityUtils.getLoginUser().getUser().getCompanyId())) {
            return AjaxResult.error("结算单不存在或非法操作");
        }
        if (statement.getAudit() != 0 && statement.getAudit() != 3) {
            return AjaxResult.error("不可操作");
        }
        statement.setAudit(1);
        statement.setSubmitTime(new Date());
        if (!updateById(statement)) {
            throw new ServiceException("提交结算单审核失败,请联系平台");
        }
        return AjaxResult.success();
    }

    @Override
    public AjaxResult manageCancel(Long id) {
        Statement statement = getById(id);
        if (statement == null || !statement.getCompanyId().equals(SecurityUtils.getLoginUser().getUser().getCompanyId())) {
            return AjaxResult.error("结算单不存在或非法操作");
        }
        if (statement.getAudit() != 1) {
            return AjaxResult.error("当前结算单不能撤回");
        }
        statement.setAudit(0);
        if (!updateById(statement)) {
            throw new ServiceException("撤回结算单审核失败,请联系平台");
        }
        return AjaxResult.success();
    }

    @Override
    public AjaxResult auditSuccess(Long id) {
        Statement statement = getById(id);
        if (statement == null || !statement.getCompanyId().equals(SecurityUtils.getLoginUser().getUser().getCompanyId())) {
            return AjaxResult.error("结算单不存在或非法操作");
        }
        if (statement.getAudit() != 1) {
            return AjaxResult.error("当前结算单不能被审核");
        }
        statement.setAudit(2);
        statement.setAuditTime(new Date());
        if (!updateById(statement)) {
            throw new ServiceException("结算单审核失败,请联系平台");
        }
        return AjaxResult.success();
    }

    @Override
    public AjaxResult auditReject(RejectDto dto) {
        Statement statement = getById(dto.getId());
        if (statement == null || !statement.getCompanyId().equals(SecurityUtils.getLoginUser().getUser().getCompanyId())) {
            return AjaxResult.error("结算单不存在或非法操作");
        }
        if (statement.getAudit() != 1) {
            return AjaxResult.error("当前结算单不能被驳回");
        }
        statement.setMsg(dto.getMsg());
        statement.setAudit(3);
        if (!updateById(statement)) {
            throw new ServiceException("结算单驳回失败,请联系平台");
        }
        return AjaxResult.success();
    }

    @Override
    public AjaxResult makeRemove(Long id) {
        Statement statement = getById(id);
        if (statement == null || !statement.getCompanyId().equals(SecurityUtils.getLoginUser().getUser().getCompanyId())) {
            return AjaxResult.error("结算单不存在或非法操作");
        }
        if (statement.getState() != 0) {
            return AjaxResult.error("当前结算单不能删除");
        }
        if (!removeById(id)) {
            throw new ServiceException("删除结算单失败,请联系平台");
        }
        return AjaxResult.success();
    }

    @Override
    public AjaxResult giveSend(StatementDto dto) throws ServerException {
        commonService.verifyCode(SecurityUtils.getLoginUser().getUser().getPhonenumber(), dto.getCode());
        Statement statement = statementMapper.calculate(dto.getId());
        if (statement == null || !statement.getCompanyId().equals(SecurityUtils.getLoginUser().getUser().getCompanyId())) {
            return AjaxResult.error("结算单不存在或非法操作");
        }
        if (statement.getAudit() != 2 && statement.getGive() != 0) {
            return AjaxResult.error("当前业务费不能发放");
        }
        Company company = companyService.getById(SecurityUtils.getLoginUser().getUser().getCompanyId());
        if (company == null) {
            return AjaxResult.error("企业信息不存在");
        }
        if (statement.getMoney().compareTo(company.getMoney()) > 0) {
            return AjaxResult.error("发放金额不能超过账户余额");
        }
        statement.setGiveTime(new Date());
        statement.setGive(1);
        if (!updateById(statement)) {
            throw new ServiceException("发放业务费失败,请联系平台");
        }
        return AjaxResult.success();
    }

    @Transactional
    @Override
    public AjaxResult payOk(Long id) throws ServerException {
        Statement statement = statementMapper.calculate(id);
        if (statement == null) {
            return AjaxResult.error("发放业务不存在");
        }
        if (statement.getGive() != 1) {
            return AjaxResult.error("当前结算业务不能发放");
        }
        Company company = companyService.getById(statement.getCompanyId());
        if (company == null) {
            return AjaxResult.error("企业信息不存在");
        }
        if (statement.getMoney().compareTo(company.getMoney()) > 0) {
            return AjaxResult.error("发放金额已超过当前企业账户余额，请提醒企业充值再进行发放");
        }
        statement.setGive(2);
        if (!updateById(statement)) {
            throw new ServiceException("当前结算业务发放失败,请联系管理员");
        }
        company.setMoney(company.getMoney().subtract(statement.getRealMoney()));
        if (!companyService.updateById(company)) {
            throw new ServiceException("更新企业余额失败,请联系管理员");
        }
        if (!statementDetailMapper.updateState(statement.getId())) {
            throw new ServiceException("更新结算单失败,请联系管理员");
        }
        Record record = new Record();
        record.setType(2);
        record.setCompanyId(statement.getCompanyId());
        record.setOpId(statement.getId());
        record.setMoney(statement.getRealMoney());
        if (!recordService.save(record)) {
            throw new ServerException("添加发放记录失败,请联系管理员");
        }
        return AjaxResult.success();
    }

    @Override
    public AjaxResult payDelete(Long id) {
        if (!removeById(id)) {
            throw new ServiceException("平台删除发放业务费失败,请联系平台");
        }
        return AjaxResult.success();
    }

    @Override
    public AjaxResult makeStatementDetailRemove(Long id) {
        StatementDetail detail = detailService.getById(id);
        if (detail == null || !detail.getCompanyId().equals(SecurityUtils.getLoginUser().getUser().getCompanyId())) {
            return AjaxResult.error("结算单明细不存在或非法操作");
        }
        if (!detailService.removeById(id)) {
            throw new ServiceException("删除结算单明细失败,请联系平台");
        }
        return AjaxResult.success();
    }
}
