package com.izouma.nineth.web;

import com.izouma.nineth.domain.Order;
import com.izouma.nineth.domain.User;
import com.izouma.nineth.dto.OrderDTO;
import com.izouma.nineth.dto.PageQuery;
import com.izouma.nineth.enums.AuthorityName;
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.repo.OrderRepo;
import com.izouma.nineth.repo.UserRepo;
import com.izouma.nineth.service.OrderService;
import com.izouma.nineth.utils.DateTimeUtils;
import com.izouma.nineth.utils.SecurityUtils;
import com.izouma.nineth.utils.SnowflakeIdWorker;
import com.izouma.nineth.utils.excel.ExcelUtils;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

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

    //@PreAuthorize("hasRole('ADMIN')")
//    @PostMapping("/save")
//    public Order save(@RequestBody Order record) {
//        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 Page<Order> all(@RequestBody PageQuery pageQuery) {
        if (!SecurityUtils.hasRole(AuthorityName.ROLE_ADMIN)) {
            pageQuery.getQuery().put("userId", SecurityUtils.getAuthenticatedUser().getId());
        }
        return orderService.all(pageQuery);
    }

    @PostMapping("/backAll")
    public Page<Order> backAll(@RequestBody PageQuery pageQuery) {
        Page<Order> all = orderService.all(pageQuery);
        List<Long> userIds = all.getContent().stream().map(Order::getUserId).distinct().collect(Collectors.toList());
        Map<Long, String> userMap = userRepo.findAllById(userIds)
                .stream()
                .collect(Collectors.toMap(User::getId, User::getNickname));
        return all.map(order -> {
            order.setNickname(userMap.get(order.getUserId()));
            return order;
        });
    }

    @GetMapping("/get/{id}")
    public Order get(@PathVariable Long id) {
        return orderRepo.findById(id).orElseThrow(new BusinessException("无记录"));
    }

//    @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,
                        @RequestHeader(value = "User-Agent") String userAgent) {
        throw new BusinessException("iOS客户端暂时无法下单，请使用H5或Android客户端");
    }

    @PostMapping("/mqCreate")
    public HashMap<String, String> mqCreate(@RequestParam Long collectionId, @RequestParam int qty,
                                            @RequestParam(required = false) Long addressId,
                                            @RequestParam(required = false) Long couponId,
                                            @RequestParam(required = false) Long invitor,
                                            @RequestParam String sign,
                                            @RequestParam(defaultValue = "false") boolean vip) {
        final User user = SecurityUtils.getAuthenticatedUser();
        return new HashMap<>() {{
            put("id", orderService.mqCreate(user.getId(), collectionId, qty, addressId, couponId, invitor, sign,
                    vip, user.getVipPurchase(), user.getVipPoint()));
        }};
    }

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

    @GetMapping("/{id}/status")
    public Object status(@PathVariable Long id) {
        Order order = orderRepo.findById(id).orElseThrow(new BusinessException("订单不存在"));
        return new HashMap<>() {{
            put("status", order.getStatus());
        }};
    }

    @PreAuthorize("hasRole('ADMIN')")
    @GetMapping("/setSales")
    public String setSales() {
        orderService.setSales();
        return "OK";
    }

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

    @PostMapping("/testNotify")
    public void testNotify(@RequestParam Long id) {
        orderService.notifyOrder(id, PayMethod.ALIPAY, new SnowflakeIdWorker(0, 0).nextId() + "");
    }

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

    @GetMapping("/checkLimit")
    public Object checkLimit(@RequestParam Long collectionId) {
        return orderService.checkLimit(collectionId, SecurityUtils.getAuthenticatedUser().getId());
    }

    @PostMapping("/cancel")
    @PreAuthorize("hasRole('ADMIN')")
    public void cancel(@RequestParam Long id) {
        orderService.cancel(id);
    }

    @GetMapping(value = "/calcSettle")
    public void calcSettle(LocalDateTime start, LocalDateTime end, HttpServletResponse response) {
        if (start == null && end == null) {
            start = LocalDate.now().minusDays(1).atStartOfDay();
            end = LocalDate.now().minusDays(1).atTime(23, 59, 59, 99999);
        }
        try {
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + DateTimeUtils.format(LocalDateTime.now(), "MMdd") + ".xlsx");
            orderService.calcSettle(start, end, response.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @PreAuthorize("hasRole('ADMIN')")
    @PostMapping("/addOrder")
    public List<Order> addOrder(@RequestParam Long collectionId, @RequestParam List<Long> userIds,
                                @RequestParam LocalDateTime time,
                                @RequestParam(defaultValue = "false") boolean notify) {
        return orderService.addOrder(collectionId, userIds, time, notify);
    }
}

