package com.izouma.nineth.web;

import cn.hutool.core.date.DateUtil;
import com.anji.captcha.util.StringUtils;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.izouma.nineth.config.RedisKeys;
import com.izouma.nineth.config.SysConstants;
import com.izouma.nineth.domain.Order;
import com.izouma.nineth.domain.User;
import com.izouma.nineth.dto.MqCreateDto;
import com.izouma.nineth.dto.OrderDTO;
import com.izouma.nineth.dto.PageQuery;
import com.izouma.nineth.dto.PageWrapDTO;
import com.izouma.nineth.dto.drawback.DrawbackDTO;
import com.izouma.nineth.enums.CollectionType;
import com.izouma.nineth.enums.OrderStatus;
import com.izouma.nineth.enums.PayMethod;
import com.izouma.nineth.exception.BusinessException;
import com.izouma.nineth.lock.RedisLockException;
import com.izouma.nineth.repo.OrderRepo;
import com.izouma.nineth.service.AssetService;
import com.izouma.nineth.service.EasyCaptchaService;
import com.izouma.nineth.service.OrderService;
import com.izouma.nineth.service.SysConfigService;
import com.izouma.nineth.utils.ApplicationContextUtil;
import com.izouma.nineth.utils.Result;
import com.izouma.nineth.utils.SecurityUtils;
import com.izouma.nineth.utils.excel.ExcelUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.math.NumberUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/order")
@Slf4j
@AllArgsConstructor
public class OrderController extends BaseController {
    private final OrderService orderService;
    private final OrderRepo orderRepo;

    private final RedisTemplate<String, Object> redisTemplate;
    private final EasyCaptchaService easyCaptchaService;
    private final AssetService assetService;
    private final SysConfigService sysConfigService;


    //@PreAuthorize("hasRole('ADMIN')")
    @PostMapping("/save")
    public Order save(@RequestBody Order record) {
        log.warn("非法请求数据,用户信息：{}, 数据：{} ", currentUser(), record);
        throw new BusinessException("不支持的操作");
//        if (record.getId() != null) {
//            Order orig = orderRepo.findById(record.getId()).orElseThrow(new BusinessException("无记录"));
//            ObjUtils.merge(orig, record);
//            return orderRepo.save(orig);
//        }
//        return orderRepo.save(record);
    }


    //@PreAuthorize("hasRole('ADMIN')")
    @PostMapping("/all")
    public PageWrapDTO<Order> all(@RequestBody PageQuery pageQuery) {
        return orderService.all(pageQuery);
    }

    @GetMapping("/get/{id}")
    public Order get(@PathVariable Long id) {
        Order order = orderService.getOrderInfo(id);
        return order;
    }

    @PostMapping("/del/{id}")
    public void del(@PathVariable Long id) {
        orderRepo.softDelete(id);
    }

    @PostMapping("/excel")
    @ResponseBody
    public void excel(HttpServletResponse response, @RequestBody PageQuery pageQuery) throws IOException {
        List<Order> data = all(pageQuery).getContent();
        ExcelUtils.export(response, data.stream().map(order -> {
            OrderDTO dto = new OrderDTO();
            BeanUtils.copyProperties(order, dto);
            dto.setStatus(Optional.ofNullable(order.getStatus()).map(OrderStatus::getDescription).orElse(null));
            dto.setPayMethod(Optional.ofNullable(order.getPayMethod()).map(PayMethod::getDescription).orElse(null));
            dto.setType(Optional.ofNullable(order.getType()).map(CollectionType::getDescription).orElse(null));
            return dto;
        }).collect(Collectors.toList()));
    }


    @PostMapping("/create")
    public Order create(@RequestParam Long collectionId, @RequestParam int qty,
                        @RequestParam(required = false) Long addressId,
                        @RequestParam(required = false) Long couponId,
                        @RequestParam(required = false) Long invitor) {
        throw new BusinessException("接口暂不可用，请刷新后重试");
    }

    @PostMapping("/mqCreate")
    public Map<String, String> mqCreate(@Validated MqCreateDto mqCreateDto) {
        //为避免 传参错误  错误参数为0
        int qty = mqCreateDto.getQty();
        if (qty <= 0 || qty >= Integer.MAX_VALUE -1){
            qty = 1;
        }
        final User user = SecurityUtils.getAuthenticatedUser();
        //Collection collection = collectionRepo.findCacheById(collectionId).orElseThrow(new BusinessException("藏品不存在"));
        BoundValueOperations<String, Object> ops = redisTemplate.boundValueOps(RedisKeys.USER_LOCK_ORDER_NUMBER + user.getId());
        Integer lockOrderNum = (Integer) ops.get();
        Integer orderLimitNumber = sysConfigService.getInt(SysConstants.LOCK_ORDER_LIMIT_NUMBER);
        if (lockOrderNum != null && lockOrderNum >= orderLimitNumber) {
            Long second = ops.getExpire();
            Long hour = second / 3600;
            Long minute = ((second - hour * 3600) / 60) + 1;
            throw new BusinessException("您的账号因锁单过多被暂时封停，剩余封停时间为" + hour + "小时" + minute + "分钟");
        }

        if (!ApplicationContextUtil.isRunDev()) {
            //非开发环境才使用
//            String redisKey  = ValidateCodeUtils.getReidsKey(user.getId());
//            BoundValueOperations ops = redisTemplate.boundValueOps(redisKey);
//            String cachedCode = (String) Objects.requireNonNullElse(ops.get(), "");
//            //删除缓存的验证码
//            redisTemplate.delete(redisKey);
//            if (!cachedCode.equals(validateCode)) {
//                throw new BusinessException("图形验证码错误");
//            }

            String key = mqCreateDto.getKey();
            String code = mqCreateDto.getCode();
            if (!easyCaptchaService.verify(RedisKeys.KAPTCHA_SESSION + user.getId(), key, code, true)) {
                throw new BusinessException("图形验证码错误");
            }
        }

        HashMap<String, String> map = new HashMap<>();
        try {
            Long collectionId = mqCreateDto.getCollectionId();
            Long addressId = mqCreateDto.getAddressId();
            Long couponId = mqCreateDto.getCouponId();
            List<Long> couponIds = mqCreateDto.getCouponIds();
            Long invitor = mqCreateDto.getInvitor();
            String id = orderService.mqCreate(user.getId(), collectionId, qty, addressId, couponId, couponIds, invitor);
            map.put("id", id);
            map.put("result", "0");
            return map;
        } catch (RedisLockException err) {
            log.error("用户锁定下单失败，用户ID:{}, 藏品ID：{}", user.getId(), mqCreateDto.getCollectionId());
            throw new BusinessException("很遗憾，藏品已售罄");
        }


    }

    @PostMapping("/hide")
    public void hide(@RequestParam Long id) {
        Order order = orderRepo.findById(id).orElseThrow(new BusinessException("订单不存在"));
        order.setHide(true);
        orderRepo.save(order);
    }

    @PostMapping("/refund")
    public void refund(@RequestParam Long id) throws WxPayException {
        throw new BusinessException("接口不再支持");
    }

    @GetMapping("/{id}/status")
    public Object status(@PathVariable String id) {
        if (!NumberUtils.isDigits(id)) {
            throw new BusinessException("请求信息错误 -" + id);
        }
        Order order = orderRepo.findById(Long.valueOf(id)).orElseThrow(new BusinessException("订单不存在"));
        return new HashMap<>() {{
            put("status", order.getStatus());
            put("projectId", order.getProjectId());
        }};
    }

    @PostMapping("/open")
    public void open(@RequestParam Long id) {
        orderRepo.findById(id).ifPresent(order -> {
            order.setOpened(true);
            orderRepo.save(order);
        });
    }

    @GetMapping("/createResult")
    public Object createResult(@RequestParam String id) {
        return orderService.queryCreateOrder(id);
    }

    //    @RequestMapping(path = "/kaptcha.jpg", method = RequestMethod.GET)
//    public void getKaptcha(HttpServletResponse response) {
//        try {
//            final User user = currentUser();
//            String value = ValidateCodeUtils.processRequest(response);
//            String rediskey = ValidateCodeUtils.getReidsKey(user.getId());
//            redisTemplate.opsForValue().set(rediskey, value, 300, TimeUnit.SECONDS);
//        } catch (Exception e) {
//            log.error("响应订单验证码失败:" + e.getMessage());
//        }
//    }

    @PostMapping(path = "/kaptcha.jpg")
    public Result getKaptcha(@RequestParam int code) {
        try {
            final User user = currentUser();
            return easyCaptchaService.gen(RedisKeys.KAPTCHA_SESSION + user.getId(), code, sysConfigService.getInt(SysConstants.GRAPH_AUTHCODE_EXPIRATION_TIME));
        } catch (Exception e) {
            log.error("响应订单验证码失败:" + e.getMessage());
            throw new BusinessException("响应订单验证码失败");
        }
    }


    @PostMapping("/excelFindAssetCollectionId")
    @ResponseBody
    public void excelFindAssetCollectionId(HttpServletResponse response, @RequestBody PageQuery pageQuery) throws IOException {
        String collectionIdStr = Objects.toString(pageQuery.getQuery().get("collectionId"),"");
        if(StringUtils.isEmpty(collectionIdStr)){
            collectionIdStr = Objects.toString(pageQuery.getQuery().get("officialCollectionId"),"");
        }
        if(StringUtils.isEmpty(collectionIdStr)){
            throw new BusinessException("需要选择一个藏品");
        }

        Long collectionId = Long.valueOf(collectionIdStr);

        String createdAtStr = Objects.toString(pageQuery.getQuery().get("createdAt"),"");
        if(StringUtils.isEmpty(createdAtStr)){
            throw new BusinessException("需要选择创建时间");
        }

        List<String> createdAtList = (List<String>)pageQuery.getQuery().get("createdAt");
        if(createdAtList == null || createdAtList.size() == 0){
            throw new BusinessException("请选择创建时间范围");
        }

        LocalDateTime startTime = DateUtil.parseLocalDateTime(createdAtList.get(0));
        LocalDateTime endTime = DateUtil.parseLocalDateTime(createdAtList.get(1));
        List<DrawbackDTO> data = assetService.findAssetCollectionId(collectionId,startTime,endTime);
        ExcelUtils.export(response, data);
    }
}

