package cn.quantgroup.customer.service.impl;

import cn.quantgroup.customer.entity.OfflineRepayOperateRecord;
import cn.quantgroup.customer.entity.OfflineRepaySubmitRecord;
import cn.quantgroup.customer.entity.OpUser;
import cn.quantgroup.customer.entity.QOfflineRepaySubmitRecord;
import cn.quantgroup.customer.enums.ApprovalStatus;
import cn.quantgroup.customer.enums.VccRepayStatusEnum;
import cn.quantgroup.customer.repo.OfflineRepayOperateRecordRepo;
import cn.quantgroup.customer.repo.OfflineRepaySubmitRecordRepo;
import cn.quantgroup.customer.rest.param.vcc.ApplyBill;
import cn.quantgroup.customer.rest.param.vcc.OfflineRepaySubmitParam;
import cn.quantgroup.customer.rest.param.vcc.UserPreRepayInfoQuery;
import cn.quantgroup.customer.rest.vo.JsonResult;
import cn.quantgroup.customer.rest.vo.vcc.QueryPreOfflineRepayVo;
import cn.quantgroup.customer.rest.vo.vcc.QuerySubmitRecordVo;
//import cn.quantgroup.customer.service.IFastDFSService;
import cn.quantgroup.customer.service.IOpSystemService;
import cn.quantgroup.customer.service.IVccService;
import cn.quantgroup.customer.service.ftp.IFtpService;
import cn.quantgroup.customer.service.http.IHttpService;
import cn.quantgroup.customer.util.IdUtil;
import cn.quantgroup.user.retbean.XUser;
import cn.quantgroup.user.vo.UserSysResult;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.Expressions;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.transaction.Transactional;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.List;

@Slf4j
@Service
public class VccServiceImpl implements IVccService {

    @Value("${vcc-talos.http}")
    private String talosHttp;
    @Autowired
    private IHttpService httpService;
    @Resource
    private OfflineRepaySubmitRecordRepo offlineRepaySubmitRecordRepo;
    @Resource
    private OfflineRepayOperateRecordRepo offlineRepayOperateRecordRepo;
    @Autowired
    private IOpSystemService IOpSystemService;
//    @Autowired
//    private IFastDFSService fastDfsService;
    @Autowired
    private IFtpService ftpService;

    @Autowired
    private UserSdkImpl userSdk;

    @Override
    public JsonResult queryPage(UserPreRepayInfoQuery query) throws Exception{
        String url = talosHttp + "/vcc/offline_pre_repay/query_page";
        JSONObject param = JSONObject.parseObject(JSON.toJSONString(query));
        log.info("queryPage | 开始请求talos获取预还款的详情，param={}",param);
        String post = httpService.post(url, param);
        log.info("queryPage | 请求talos结束，param={}，result={}",param,post);
        if (StringUtils.isBlank(post)){
            log.error("queryPage | 请求talos异常，返回值为空，param={}",query);
            return JsonResult.buildErrorStateResult("请求talos获取详情异常:没有请求通");
        }
        JSONObject jsonObject = JSONObject.parseObject(post);
        if (!"0000".equals(jsonObject.getString("code")) || !"0000".equals(jsonObject.getString("businessCode"))){
            log.error("queryPage | talos没有正确查询出结果：" + jsonObject.getString("msg"));
            return JsonResult.buildErrorStateResult("talos没有正确查询出结果：" + jsonObject.getString("msg"));
        }
        JSONObject data = jsonObject.getJSONObject("data");
        JSONArray list = data.getJSONArray("list");
        List<QueryPreOfflineRepayVo> voList = new Gson().fromJson(list.toString(), new TypeToken<List<QueryPreOfflineRepayVo>>() {
        }.getType());
        for (int i = 0;i<voList.size();i++){
            if (1 == query.getRepayType()){
                ApplyBill applyBill = new ApplyBill();
                applyBill.setBillId(Long.parseLong(voList.get(i).getUniqueId()));
                applyBill.setAmount(voList.get(i).getCurrBall());
                List<OfflineRepaySubmitRecord> byUserIdEqualsAndRepayTypeEquals = offlineRepaySubmitRecordRepo.findByUserIdEqualsAndRepayTypeEquals(voList.get(i).getUserId(), 1);
                if (!CollectionUtils.isEmpty(byUserIdEqualsAndRepayTypeEquals)){
                    for (OfflineRepaySubmitRecord record:byUserIdEqualsAndRepayTypeEquals){
                        List<ApplyBill> billList = new Gson().fromJson(record.getBills(), new TypeToken<List<ApplyBill>>() {
                        }.getType());
                        log.info("billList={}，applyBill={}",billList,applyBill);
                        if (billList.contains(applyBill)){
                            log.info("发现已经提交过了，补充流水号前：voList={}",voList);
                            voList.get(i).setSerialNo(record.getSerialNo());
                            voList.get(i).setApprovalStatus(record.getApprovalStatus());
                            log.info("发现已经提交过了，补充流水号后：voList={}",voList);
                            break;
                        }
                    }
                }
            }else {
                OfflineRepaySubmitRecord firstByUniqueIdEquals = offlineRepaySubmitRecordRepo.findFirstByUniqueIdEquals(voList.get(i).getUniqueId());
                if (Objects.nonNull(firstByUniqueIdEquals)){
                    voList.get(i).setSerialNo(firstByUniqueIdEquals.getSerialNo());
                    voList.get(i).setApprovalStatus(firstByUniqueIdEquals.getApprovalStatus());
                }
            }
        }
        Map<String,Object> map = new HashMap<>();
        map.put("count",data.get("count"));
        map.put("type",data.get("type"));
        map.put("list",voList);
        log.info("voList={}",voList);
        return JsonResult.buildSuccessResult("请求成功",map);
    }

    @Override
    public JsonResult queryRepayCalDetail(String uniqueId, Integer repayType) throws Exception {
        String url = talosHttp + "/vcc/offline_pre_repay/detail?uniqueId=" + uniqueId + "&repayType=" + repayType;
        log.info("queryRepayCalDetail | 开始请求talos,url={}",url);
        String get = httpService.get(url);
        log.info("queryRepayCalDetail | 请求talos结束，get={}",get);
        if (StringUtils.isBlank(get)){
            log.error("queryRepayCalDetail | 请求talos异常，返回值为空");
            return JsonResult.buildErrorStateResult("请求talos获取详情异常:没有请求通");
        }
        JSONObject jsonObject = JSONObject.parseObject(get);
        if (!"0000".equals(jsonObject.getString("code")) || !"0000".equals(jsonObject.getString("businessCode"))){
            log.error("queryRepayCalDetail | talos没有正确查询出结果:" + jsonObject.getString("msg"));
            return JsonResult.buildErrorStateResult("talos没有正确查询出结果：" + jsonObject.getString("msg"));
        }
        JSONObject data = jsonObject.getJSONObject("data");
        return JsonResult.buildSuccessResult("请求成功",data);
    }

    @Override
    @Transactional
    public void saveSubmitRecord(OfflineRepaySubmitParam param,String token) throws Exception{
        String serialNo = IdUtil.generateSequenceNo();
        if (1 == param.getRepayType()){
            //月还账单
            List<ApplyBill> list = param.getList();

            List<OfflineRepaySubmitRecord> byUserIdEqualsAndRepayTypeEquals = offlineRepaySubmitRecordRepo.findByUserIdEqualsAndRepayTypeEqualsAndApprovalStatusNot(param.getUserId(), 1,2);
            if (!CollectionUtils.isEmpty(byUserIdEqualsAndRepayTypeEquals)){
                for (OfflineRepaySubmitRecord record:byUserIdEqualsAndRepayTypeEquals){
                    List<ApplyBill> billList = new Gson().fromJson(record.getBills(), new TypeToken<List<ApplyBill>>() {
                    }.getType());
                    if (!Collections.disjoint(list,billList)){
                        log.error("saveSubmitRecord | 提交时发现已经提交过了，请确认,newBills={},existBills={}",list.toString(),billList.toString());
                        throw new Exception("提交时发现已经提交过了，请确认,newBills="+list.toString()+",existBills="+billList.toString());
                    }
                }
            }
            OfflineRepaySubmitRecord record = new OfflineRepaySubmitRecord();
            BeanUtils.copyProperties(param,record);
            record.setSerialNo(serialNo);
            record.setBills(JSONObject.toJSONString(list));
            String replace = param.getCredentialsAddress().toString().replace("[", "").replace("]", "");
            record.setCredentialsAddress(replace);
            record.setApprovalStatus(0);
            offlineRepaySubmitRecordRepo.save(record);
        }else {
            OfflineRepaySubmitRecord firstByUniqueIdEquals = offlineRepaySubmitRecordRepo.findFirstByUniqueIdEqualsAndApprovalStatusNot(param.getUniqueId(),2);
            if (Objects.nonNull(firstByUniqueIdEquals)){
                log.error("saveSubmitRecord | 提交时发现已经提交过了，请确认,uniqueId={}",param.getUniqueId());
                throw new Exception("提交时发现已经提交过了，请确认,uniqueId="+param.getUniqueId());
            }
            OfflineRepaySubmitRecord record = new OfflineRepaySubmitRecord();
            BeanUtils.copyProperties(param,record);
            record.setSerialNo(serialNo);
            String replace = param.getCredentialsAddress().toString().replace("[", "").replace("]", "");
            record.setCredentialsAddress(replace);
            record.setApprovalStatus(0);
            offlineRepaySubmitRecordRepo.save(record);
        }

        //保存操作人记录
        saveApprovalRecord(serialNo,"", 0 ,token);
    }

    @Override
    public OfflineRepaySubmitParam approvalQuery(String serialNo) throws Exception {
        OfflineRepaySubmitRecord bySerialNoEquals = offlineRepaySubmitRecordRepo.findBySerialNoEquals(serialNo);
        if (Objects.isNull(bySerialNoEquals)){
            log.error("approvalQuery | 没有查询到这条申请记录，请确认：serialNo = {}",serialNo);
            throw new Exception("没有查询到这条申请记录，请确认：serialNo = " + serialNo);
        }
        OfflineRepaySubmitParam param = new OfflineRepaySubmitParam();
        BeanUtils.copyProperties(bySerialNoEquals,param);
        List<ApplyBill> billList = new Gson().fromJson(bySerialNoEquals.getBills(), new TypeToken<List<ApplyBill>>() {
        }.getType());
        param.setList(billList);
        String[] split = bySerialNoEquals.getCredentialsAddress().split(",");
        List<String> list = Arrays.asList(split);
//        List<String> addressList = new ArrayList<>();
//        for (String baseUrl:list){
////            String viewUrl = fastDfsService.toUrl(baseUrl);
////            addressList.add(viewUrl);
//            byte[] down = ftpService.down(baseUrl);
//            addressList.add(Base64.getEncoder().encodeToString(down));
//        }
        param.setCredentialsAddress(list);
        return param;
    }

    @Override
    public JsonResult queryApprovalRecord(String serialNo) throws Exception {
        List<OfflineRepayOperateRecord> bySerialNoEquals = offlineRepayOperateRecordRepo.findBySerialNoEquals(serialNo);
        return JsonResult.buildSuccessResult("请求成功",bySerialNoEquals);
    }

    @Override
    @Transactional
    public void approvalResult(String serialNo, String remark, Integer status ,String token) throws Exception {
        OfflineRepaySubmitRecord bySerialNoEquals = offlineRepaySubmitRecordRepo.findBySerialNoEqualsAndApprovalStatusEquals(serialNo,0);
        if (Objects.isNull(bySerialNoEquals)){
            log.error("approvalQuery | 没有查询到这条申请记录，请确认：serialNo = {}",serialNo);
            throw new Exception("没有查询到这条申请记录，请确认：serialNo = " + serialNo);
        }
        if ( 0 == status){
            //审批拒绝
            bySerialNoEquals.setApprovalStatus(2);
            offlineRepaySubmitRecordRepo.save(bySerialNoEquals);
            saveApprovalRecord(serialNo,remark,2,token);
        }else if (1== status){
            //审批通过
            String url = "";
//            String phone = bySerialNoEquals.getPhone();
//            UserSysResult<XUser> userByPhoneNo = userSdk.getService().findUserByPhoneNo(phone);
//            if (userByPhoneNo == null || !userByPhoneNo.isSuccess() || userByPhoneNo.getData() == null) {
//                throw new RuntimeException("用户中心接口findUserDetailByPhone返回失败");
//            }
            if ( 1 == bySerialNoEquals.getRepayType()){
                //月还账单
                List<ApplyBill> billList = new Gson().fromJson(bySerialNoEquals.getBills(), new TypeToken<List<ApplyBill>>() {
                }.getType());
                StringBuilder stringBuilder = new StringBuilder();
                for (ApplyBill applyBill:billList){
                    stringBuilder.append(applyBill.getBillId()).append(",");
                }
                String billNo = stringBuilder.substring(0,stringBuilder.lastIndexOf(","));
                url = talosHttp + "/vcc/repay/offlineRepay?userId=" + bySerialNoEquals.getUserId() + "&amount=" + bySerialNoEquals.getAmount() + "&billNo=" + billNo;
            }else {
                //提前结清
                url = talosHttp + "/vcc/offline_pre_repay/repay?userId=" + bySerialNoEquals.getUserId() + "&amount=" + bySerialNoEquals.getAmount()
                        + "&repayType=" + bySerialNoEquals.getRepayType() + "&uniqueId=" + bySerialNoEquals.getUniqueId();
            }
            log.info("queryRepayCalDetail | 开始请求talos,url={}",url);
            String get = httpService.get(url);
            log.info("queryRepayCalDetail | 请求talos结束，get={}",get);
            if (StringUtils.isBlank(get)){
                log.error("queryRepayCalDetail | 请求talos异常，返回值为空");
                throw new Exception("请求talos异常:没有请求通");
            }
            JSONObject jsonObject = JSONObject.parseObject(get);
            if (!"0000".equals(jsonObject.getString("code")) || !"0000".equals(jsonObject.getString("businessCode"))){
                log.error("queryRepayCalDetail | 请求talos处理失败，msg={}",jsonObject.getString("msg"));
                throw new Exception("请求talos处理失败:"+jsonObject.getString("msg"));
            }
            bySerialNoEquals.setApprovalStatus(1);
            offlineRepaySubmitRecordRepo.save(bySerialNoEquals);
            saveApprovalRecord(serialNo,remark,1,token);
        }
    }

    @Override
    public Map<String,String> fileUpload(MultipartFile file) throws Exception {
//        String name = file.getOriginalFilename();
//        log.info("fileUpload | filename={}",name);
//        String substring = name.substring(name.lastIndexOf(".") + 1);
//        String baseUrl = fastDfsService.uploadFile(file.getBytes(), substring);
//        String viewUrl = fastDfsService.toUrl(baseUrl);
//        Map<String,String> map = new HashMap<>();
//        map.put("baseUrl",baseUrl);
//        map.put("viewUrl",viewUrl);
//        return map;

        String fileName = file.getOriginalFilename();
        byte[] bytes = file.getBytes();
        Map<String, Object> paramMap = new HashMap<>(8);
        paramMap.put("fileName", fileName);
        paramMap.put("fileBytes", bytes);
        String filePath = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) + "/";
        paramMap.put("filePath", filePath);
        ftpService.send(paramMap, 3);
        Map<String,String> map = new HashMap<>();
        map.put("base64",Base64.getEncoder().encodeToString(bytes));
        map.put("url",filePath + fileName);
        return map;
    }

    @Override
    public JsonResult queryApplyRecord(UserPreRepayInfoQuery query) throws Exception {
        BooleanExpression booleanExpression = Expressions.asBoolean(true).isTrue();

        if (StringUtils.isNotBlank(query.getUserId())){
            booleanExpression = booleanExpression.and(QOfflineRepaySubmitRecord.offlineRepaySubmitRecord.userId.eq(Integer.valueOf(query.getUserId())));
        }
        if (StringUtils.isNotBlank(query.getPhone())){
            booleanExpression =  booleanExpression.and(QOfflineRepaySubmitRecord.offlineRepaySubmitRecord.phone.eq(query.getPhone()));
        }
        if (query.getApprovalStatus() != null){
            booleanExpression = booleanExpression.and(QOfflineRepaySubmitRecord.offlineRepaySubmitRecord.approvalStatus.eq(query.getApprovalStatus()));
        }
        if (query.getRepayType() != null){
            booleanExpression = booleanExpression.and(QOfflineRepaySubmitRecord.offlineRepaySubmitRecord.repayType.eq(query.getRepayType()));
        }
        if (StringUtils.isNotBlank(query.getOrderNo())){
            booleanExpression = booleanExpression.and(QOfflineRepaySubmitRecord.offlineRepaySubmitRecord.uniqueId.eq(query.getOrderNo()));
        }
        if (StringUtils.isNotBlank(query.getBillId())){
            if (1 == query.getRepayType()){
                booleanExpression = booleanExpression.and(QOfflineRepaySubmitRecord.offlineRepaySubmitRecord.bills.contains(query.getBillId()));
            }else {
                booleanExpression = booleanExpression.and(QOfflineRepaySubmitRecord.offlineRepaySubmitRecord.uniqueId.eq(query.getBillId()));
            }
        }

        long count = offlineRepaySubmitRecordRepo.count(booleanExpression);
        int offset = (query.getPageIndex() -1) * query.getPageSize();
        Page<OfflineRepaySubmitRecord> plantPage = offlineRepaySubmitRecordRepo.findAll(booleanExpression, new PageRequest(offset, query.getPageSize()));
        List<OfflineRepaySubmitRecord> content = plantPage.getContent();
        List<QuerySubmitRecordVo> submitRecordVoList = new ArrayList<>();
        for (OfflineRepaySubmitRecord record : content){
            QuerySubmitRecordVo submitRecordVo = new QuerySubmitRecordVo();
            BeanUtils.copyProperties(record,submitRecordVo);
            submitRecordVo.setRepayStatusName(VccRepayStatusEnum.getDescByValue(submitRecordVo.getRepayStatus()));
            submitRecordVo.setApprovalStatusName(ApprovalStatus.getDescByValue(submitRecordVo.getApprovalStatus()));
            if ( 1 == submitRecordVo.getRepayType()) {
                //月还账单
                List<ApplyBill> billList = new Gson().fromJson(submitRecordVo.getBills(), new TypeToken<List<ApplyBill>>() {
                }.getType());
                StringBuilder stringBuilder = new StringBuilder();
                for (ApplyBill applyBill : billList) {
                    stringBuilder.append(applyBill.getBillId()).append(",");
                }
                String billNo = stringBuilder.substring(0, stringBuilder.lastIndexOf(","));
                submitRecordVo.setUniqueId(billNo);
            }
            submitRecordVoList.add(submitRecordVo);
        }
        Map<String,Object> map = new HashMap<>();
        map.put("count",count);
        map.put("type",query.getRepayType());
        map.put("list",submitRecordVoList);
        return JsonResult.buildSuccessResult("请求成功",map);
    }

    @Override
    public void saveApprovalRecord(String serialNo, String remark, Integer status, String token) throws Exception {

        JsonResult<OpUser> opUserResult = IOpSystemService.findUserByToken(token, null);
        if (Objects.isNull(opUserResult) || !opUserResult.isSuccess()) {
            log.error("根据token查询不到用户信息 token:{}", token);
            return;
        } else {
            OpUser opUser = opUserResult.getData();
            OfflineRepayOperateRecord record = new OfflineRepayOperateRecord();
            record.setSerialNo(serialNo);
            record.setOperateAccount(opUser.getUser());
            record.setOperateName(opUser.getName());
            if (0 == status){
                record.setOperateContent("已提交");
            }else if (1 == status){
                record.setOperateContent("审批通过");
            }else if (2 == status){
                record.setOperateContent("审批拒绝");
            }
            record.setOperateTime(new Date());
            record.setRemark(remark);
            offlineRepayOperateRecordRepo.save(record);
        }
    }

}
