package com.zhiqiyun.open.mvc.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dliyun.oap.framework.security.algorithm.Rsa;
import com.dliyun.oap.framework.service.RouterService;
import com.dliyun.oap.framework.service.ServiceMethodHandler;
import com.zhiqiyun.open.annotation.Permission;
import com.zhiqiyun.open.core.enmus.YN;
import com.zhiqiyun.open.core.models.app.ApiRequestLog;
import com.zhiqiyun.open.core.models.app.AppKeyInfo;
import com.zhiqiyun.open.core.service.ApiRequestLogService;
import com.zhiqiyun.open.core.service.AppKeyInfoService;
import com.zhiqiyun.open.core.service.SequenceService;
import com.zhiqiyun.open.mvc.Result;
import com.zhiqiyun.open.mvc.params.QueryApiRequestLogParams;
import com.zhiqiyun.open.mvc.params.QueryAppKeyInfoParams;
import com.zhiqiyun.open.mvc.params.SaveAppKeyInfoParam;
import com.zhiqiyun.open.utils.DateUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/appKey")
public class AppKeyInfoController {

    @Autowired
    private AppKeyInfoService appKeyInfoService;

    @Autowired
    private SequenceService sequenceService;

    @Autowired
    private ApiRequestLogService apiRequestLogService;

    @Autowired
    private RouterService routerService;

    @Permission(value = "app.key.find", tags = "查询AppKey")
    @PostMapping("/findPage")
    public Result findPage(@RequestBody QueryAppKeyInfoParams params) {

        QueryWrapper<AppKeyInfo> queryWrapper = new QueryWrapper<>();
        if (params.getId() != null) {
            queryWrapper.eq("id", params.getId());
        }
        if (params.getIsEnable() != null) {
            queryWrapper.eq("is_enable", params.getIsEnable());
        }
        if (StringUtils.isNotBlank(params.getRemark())) {
            queryWrapper.like("remark", params.getRemark());
        }

        Page<AppKeyInfo> page = params.getPage();
        page.addOrder(OrderItem.desc("created_time"));

        Page<AppKeyInfo> resultData = this.appKeyInfoService.page(page, queryWrapper);

        return Result.instance(Result.Code.SUCCESS).setData(resultData);
    }


    @Permission(value = "app.key.statistics", tags = "Api接口统计")
    @PostMapping("/statistics")
    public Result statistics() {
        QueryWrapper<ApiRequestLog> wrapper = new QueryWrapper<>();
        wrapper.select("app_key appKey", "count(id) value");
        wrapper.groupBy("app_key");
        wrapper.orderByDesc("value");
        wrapper.last("limit 8");
        List<Map<String, Object>> requestAppKeyData = this.apiRequestLogService.listMaps(wrapper);
        for (Map<String, Object> dataMap : requestAppKeyData) {
            AppKeyInfo appKeyInfo = this.appKeyInfoService.findByAppKey(dataMap.get("appKey").toString());
            if (appKeyInfo == null) {
                dataMap.put("name", "未知应用");
            } else {
                dataMap.put("name", appKeyInfo.getName());
            }
        }

        wrapper = new QueryWrapper<>();
        wrapper.select("DATE_FORMAT(service_begin_time, '%Y-%m-%d') d", "count(id) value");
        wrapper.groupBy("d");
        wrapper.orderByAsc("d");
        wrapper.last("limit 15");
        List<Map<String, Object>> requestDayData = this.apiRequestLogService.listMaps(wrapper);


        wrapper = new QueryWrapper<>();
        wrapper.select("method", "count(id) value");
        wrapper.groupBy("method");
        wrapper.orderByDesc("value");
        wrapper.last("limit 15");
        List<Map<String, Object>> requestMethodData = this.apiRequestLogService.listMaps(wrapper);
        for (Map<String, Object> dataMap : requestMethodData) {
            String method = dataMap.getOrDefault("method", "").toString();

            if (StringUtils.isBlank(method)) {
                dataMap.put("name", "未知应用");
            } else {
                dataMap.put("name", method);
            }
        }

        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("requestAppKeyData", requestAppKeyData);
        dataMap.put("requestDayData", requestDayData);
        dataMap.put("requestMethodData", requestMethodData);

        return Result.instance(Result.Code.MESSAGE_SUCCESS).setData(dataMap);
    }

    @Permission(value = "app.key.find", tags = "Api调用日志查询")
    @PostMapping("/findRequestLogsPage")
    public Result findRequestLogsPage(@RequestBody QueryApiRequestLogParams params) {

        QueryWrapper<ApiRequestLog> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(params.getAppKey())) {
            queryWrapper.eq("app_key", params.getAppKey());
        }
        if (StringUtils.isNotBlank(params.getMethod())) {
            queryWrapper.eq("method", params.getMethod());
        }
        if (StringUtils.isNotBlank(params.getVersion())) {
            queryWrapper.eq("version", params.getVersion());
        }
        if (StringUtils.isNotBlank(params.getClientIp())) {
            queryWrapper.eq("client_ip", params.getClientIp());
        }
        if (params.getServiceBeginTime() != null) {
            queryWrapper.between("service_begin_time", params.getServiceBeginTime().getStatDate(), params.getServiceBeginTime().getEndDate());
        }


        Page<ApiRequestLog> page = params.getPage();
        page.addOrder(OrderItem.desc("service_begin_time"));

        Page<ApiRequestLog> resultData = this.apiRequestLogService.page(page, queryWrapper);

        return Result.instance(Result.Code.SUCCESS).setData(resultData);
    }

    @Permission(value = "app.key.add", tags = "新建AppKey")
    @PostMapping("/save")
    public Result save(@Valid @RequestBody SaveAppKeyInfoParam param) throws Exception {

        Map<String, ServiceMethodHandler> serviceMethodHandlerMap = this.routerService.getOapContext().getAllServiceMethodHandlers();

        List<String> listAllServices = new ArrayList<>();
        for (ServiceMethodHandler handler : serviceMethodHandlerMap.values()) {
            listAllServices.add(String.format("%s:%s", handler.getServiceMethodDefinition().getMethod(), handler.getServiceMethodDefinition().getVersion()));
        }

        AppKeyInfo appKeyInfo = new AppKeyInfo();
        BeanUtils.copyProperties(param, appKeyInfo);

        Long id = this.sequenceService.nextId();
        appKeyInfo.setId(id);
        Rsa.RsaKeys rsaKeys = Rsa.genKeyPair();
        appKeyInfo.setPublicKey(rsaKeys.getPublicKey());
        appKeyInfo.setPrivateKey(rsaKeys.getPrivateKey());
        appKeyInfo.setCreatedTime(DateUtil.current());
        appKeyInfo.setIsEnable(YN.Y);
        appKeyInfo.getPermissions().removeIf(permission -> !listAllServices.contains(permission));

        this.appKeyInfoService.save(appKeyInfo);

        return Result.instance(Result.Code.MESSAGE_SUCCESS);
    }

    @Permission(value = "app.key.edit", tags = "更新AppKey")
    @PostMapping("/updateById")
    public Result updateById(Long id, @Valid @RequestBody SaveAppKeyInfoParam param) {
        Map<String, ServiceMethodHandler> serviceMethodHandlerMap = this.routerService.getOapContext().getAllServiceMethodHandlers();

        List<String> listAllServices = new ArrayList<>();
        for (ServiceMethodHandler handler : serviceMethodHandlerMap.values()) {
            listAllServices.add(String.format("%s:%s", handler.getServiceMethodDefinition().getMethod(), handler.getServiceMethodDefinition().getVersion()));
        }

        AppKeyInfo appKeyInfo = new AppKeyInfo();
        BeanUtils.copyProperties(param, appKeyInfo);
        appKeyInfo.setId(id);
        appKeyInfo.getPermissions().removeIf(permission -> !listAllServices.contains(permission));
        this.appKeyInfoService.refreshCache(id.toString());
        this.appKeyInfoService.updateById(appKeyInfo);


        return Result.instance(Result.Code.MESSAGE_SUCCESS);
    }

    @Permission(value = "app.key.disable", tags = "禁用AppKey")
    @PostMapping("/disableByIds")
    public Result disableByIds(@RequestBody List<Long> ids) {
        UpdateWrapper<AppKeyInfo> updateWrapper = new UpdateWrapper<>();
        updateWrapper.in("id", ids);
        updateWrapper.set("is_enable", YN.N);
        this.appKeyInfoService.update(updateWrapper);
        return Result.instance(Result.Code.MESSAGE_SUCCESS);
    }

    @Permission(value = "app.key.enable", tags = "启用AppKey")
    @PostMapping("/enableByIds")
    public Result enableByIds(@RequestBody List<Long> ids) {
        UpdateWrapper<AppKeyInfo> updateWrapper = new UpdateWrapper<>();
        updateWrapper.in("id", ids);
        updateWrapper.set("is_enable", YN.Y);
        this.appKeyInfoService.update(updateWrapper);
        return Result.instance(Result.Code.MESSAGE_SUCCESS);
    }
}
