package com.bizzan.bitrade.controller;

import com.alibaba.fastjson.JSON;
import com.bizzan.bitrade.annotation.AccessLog;
import com.bizzan.bitrade.constant.AdminModule;
import com.bizzan.bitrade.constant.PageModel;
import com.bizzan.bitrade.entity.*;
import com.bizzan.bitrade.entity.transform.AuthMember;
import com.bizzan.bitrade.model.ContractOrderEntrustScreen;
import com.bizzan.bitrade.model.ContractOrderEntrustVo;
import com.bizzan.bitrade.service.ContractCoinService;
import com.bizzan.bitrade.service.ContractOrderEntrustService;
import com.bizzan.bitrade.service.LocaleMessageSourceService;
import com.bizzan.bitrade.service.MemberService;
import com.bizzan.bitrade.service.MemberWeightUpperService;
import com.bizzan.bitrade.util.MessageResult;
import com.bizzan.bitrade.util.PredicateUtils;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.BooleanExpression;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Sort;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.SessionAttribute;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;

import static com.bizzan.bitrade.constant.SysConstant.SESSION_MEMBER;
import static com.bizzan.bitrade.entity.QMember.member;
import static com.bizzan.bitrade.entity.QMemberApplication.memberApplication;

@RestController
@RequestMapping("/swap/order")
@Slf4j
public class ContractOrderEntrustController extends BaseController {
    @Autowired
    private ContractOrderEntrustService contractOrderEntrustService;

    @Autowired
    private MemberService memberService;

    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;

    @Autowired
    private ContractCoinService contractCoinService;

    @Autowired
    private MemberWeightUpperService memberWeightUpperService;

    @Autowired
    private LocaleMessageSourceService msService;

//    @RequiresPermissions("swap-coin:page-query")
    @PostMapping("/coin/page-query")
    @AccessLog(module = AdminModule.CONTRACTOPTION, operation = "期权合约交易对 列表")
    public MessageResult list(
            PageModel pageModel) {

        if (pageModel.getProperty() == null) {
            List<String> list = new ArrayList<>();
            list.add("sort");
            List<Sort.Direction> directions = new ArrayList<>();
            directions.add(Sort.Direction.DESC);
            pageModel.setProperty(list);
            pageModel.setDirection(directions);
        }
        Page<ContractCoin> coinList = contractCoinService.findAll(null, pageModel.getPageable());

        return success(coinList);
    }

    /**
     * 分页查询
     * @param pageModel
     * @param screen
     * @return
     */
    @RequiresPermissions("swap:order:page-query")
    @PostMapping("page-query")
    @AccessLog(module = AdminModule.CONTRACTOPTION, operation = "期权合约订单 列表")
    public MessageResult pageQuery(
            PageModel pageModel,
            ContractOrderEntrustScreen screen,
            @SessionAttribute(SESSION_MEMBER) AuthMember user) {
        long t0 = System.currentTimeMillis();
        log.info("[pageQuery] 开始 memberId={}, screen={}", user.getId(), JSON.toJSONString(screen));

        // 1. 默认排序
        if (pageModel.getDirection() == null && pageModel.getProperty() == null) {
            ArrayList<Sort.Direction> directions = new ArrayList<>();
            directions.add(Sort.Direction.DESC);
            pageModel.setDirection(directions);
            List<String> property = new ArrayList<>();
            property.add("createTime");
            pageModel.setProperty(property);
        }
        log.info("[pageQuery] step1 排序设置完成, {}ms", System.currentTimeMillis() - t0);

        // 2. 代理商校验
        Member checkMember = memberService.findOne(user.getId());
        if(!checkMember.getSuperPartner().equals("1")) {
            log.error("[pageQuery] 非代理商访问 memberId={}, {}ms", user.getId(), System.currentTimeMillis() - t0);
            return error("您不是代理商！");
        }
        log.info("[pageQuery] step2 代理商校验通过, {}ms", System.currentTimeMillis() - t0);

        // 3. 构建查询条件
        Predicate predicate = getPredicate(screen, user.getId());
        log.info("[pageQuery] step3 查询条件构建完成, {}ms", System.currentTimeMillis() - t0);

        // 4. 分页查询
        Page<ContractOrderEntrust> all = contractOrderEntrustService.findAll(predicate, pageModel.getPageable());
        log.info("[pageQuery] step4 DB查询完成, 总数={}, 本页={}, {}ms",
                all.getTotalElements(), all.getNumberOfElements(), System.currentTimeMillis() - t0);

        // 5. 组装 VO（含逐条查用户名）
        List<ContractOrderEntrustVo> retList = new ArrayList<>();
        for (ContractOrderEntrust order : all) {
            ContractOrderEntrustVo vo = new ContractOrderEntrustVo();
            BeanUtils.copyProperties(order, vo);
            vo.setUsername(memberService.findUserNameById(order.getMemberId()));
            retList.add(vo);
        }
        log.info("[pageQuery] step5 VO组装完成, 共{}条, {}ms", retList.size(), System.currentTimeMillis() - t0);

        Page<ContractOrderEntrustVo> newAll = new PageImpl<>(retList, pageModel.getPageable(), all.getTotalElements());

        log.info("[pageQuery] 完成, 总耗时{}ms", System.currentTimeMillis() - t0);
        return success(newAll);
    }

    private Predicate getPredicate(ContractOrderEntrustScreen screen,Long userId) {
        ArrayList<BooleanExpression> booleanExpressions = new ArrayList<>();
        QContractOrderEntrust qContractOrderEntrust = QContractOrderEntrust.contractOrderEntrust;
        if (screen.getContractId() != null) {
            booleanExpressions.add(qContractOrderEntrust.contractId.eq(screen.getContractId()));
        }
    	SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        if(screen.getStartTime() != null && !screen.getStartTime().equals("")) {
        	try {
        		long startTime = sdf.parse(screen.getStartTime()).getTime();
        		booleanExpressions.add(qContractOrderEntrust.createTime.goe(startTime));
        	} catch(ParseException e) {
        		
        	}
        }
        if(screen.getEndTime() != null && !screen.getEndTime().equals("")) {
        	try {
	        	long endTime = sdf.parse(screen.getEndTime()).getTime()+24*60*60000;
	            booleanExpressions.add(qContractOrderEntrust.createTime.loe(endTime));
        	} catch(ParseException e) {
        		
        	}
        }
        //if(screen.getDirection() != null) {
        //    booleanExpressions.add(qContractOrderEntrust.direction.eq(screen.getDirection()));
        //}
        if(screen.getEntrustType() != null) {
            booleanExpressions.add(qContractOrderEntrust.entrustType.eq(screen.getEntrustType()));
        }
        if(screen.getIsBlast() != null) {
            booleanExpressions.add(qContractOrderEntrust.isBlast.eq(screen.getIsBlast()));
        }
        if(screen.getIsFromSpot() != null) {
            booleanExpressions.add(qContractOrderEntrust.isFromSpot.eq(screen.getIsFromSpot()));
        }
        if(screen.getMemberId() != null) {
            booleanExpressions.add(qContractOrderEntrust.memberId.eq(screen.getMemberId()));
        }
        if(screen.getStatus() == null || screen.getStatus() ==ContractOrderEntrustStatus.ENTRUST_ING) {
            booleanExpressions.add(qContractOrderEntrust.status.eq(ContractOrderEntrustStatus.ENTRUST_ING));
        } else {
        	booleanExpressions.add(qContractOrderEntrust.status.ne(ContractOrderEntrustStatus.ENTRUST_ING));
        }
        if(screen.getType() != null) {
            booleanExpressions.add(qContractOrderEntrust.type.eq(screen.getType()));
        }
        if(screen.getVolume() != null) {
            booleanExpressions.add(qContractOrderEntrust.volume.goe(screen.getVolume()));
        }
        if(StringUtils.isNotEmpty(screen.getPhone())) {
            Member member = memberService.findByPhone(screen.getPhone());
            booleanExpressions.add(qContractOrderEntrust.memberId.eq(member.getId()));
        }
        if(StringUtils.isNotEmpty(screen.getEmail())) {
            Member member = memberService.findByEmail(screen.getEmail());
            booleanExpressions.add(qContractOrderEntrust.memberId.eq(member.getId()));
        }
        if(StringUtils.isNotEmpty(screen.getUsername())) {
            Member member = memberService.findByUsername(screen.getUsername());
            booleanExpressions.add(qContractOrderEntrust.memberId.eq(member.getId()));
        }
        if(screen.getProfitAndLoss() != null) {
            booleanExpressions.add(qContractOrderEntrust.profitAndLoss.gt(screen.getProfitAndLoss()));
        }
        /*List<Member> memberList = memberService.findByInviterId(userId);
        Long[] ids = new Long[memberList.size()];
        for (int i =0;i<memberList.size();i++){
            ids[i]=memberList.get(i).getId();
        }*/
        List<Long> subIds = memberWeightUpperService.findMemberIdListByAllUppers(userId);
        subIds.add(userId);
        booleanExpressions.add(qContractOrderEntrust.memberId.in(subIds));
        return PredicateUtils.getPredicate(booleanExpressions);
    }

    /**
     * 撤销委托
     * @param orderId
     * @return
     */
    @RequiresPermissions("swap:order:cancel")
    @PostMapping("cancel")
    @AccessLog(module = AdminModule.CONTRACTOPTION, operation = "永续合约 撤单")
    public MessageResult cancelOrder(Long orderId) {
        ContractOrderEntrust order = contractOrderEntrustService.findOne(orderId);
        if(order == null) {
            return MessageResult.error(msService.getMessage("REVOKE_ENTRUST_FAILED"));
        }
        if(order.getStatus() != ContractOrderEntrustStatus.ENTRUST_ING) {
            return MessageResult.error(msService.getMessage("ENTRUST_STATUS_ERROR"));
        }
        // 发送消息至Exchange系统
        kafkaTemplate.send("swap-order-cancel", JSON.toJSONString(order));

        log.info(">>>>>>>>>>订单撤销提交完成>>>>>>>>>>");
        return MessageResult.success("操作成功");
    }
}
