package com.diagbot.facade;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.diagbot.dto.ProductServiceDTO;
import com.diagbot.entity.LantoneProduct;
import com.diagbot.entity.OpenedProducts;
import com.diagbot.entity.ProductService;
import com.diagbot.entity.ServiceInfo;
import com.diagbot.entity.ServiceToken;
import com.diagbot.entity.wrapper.ProductServiceWrapper;
import com.diagbot.enums.IsDeleteEnum;
import com.diagbot.enums.ServiceTypeEnum;
import com.diagbot.enums.StatusEnum;
import com.diagbot.enums.TokenTypeEnum;
import com.diagbot.exception.CommonErrorCode;
import com.diagbot.exception.CommonException;
import com.diagbot.service.impl.ProductServiceServiceImpl;
import com.diagbot.util.DateUtil;
import com.diagbot.util.EntityUtil;
import com.diagbot.util.GuidUtil;
import com.diagbot.util.UserUtils;
import com.diagbot.vo.ProductServiceSaveVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @Description:产品与用户端关联业务层
 * @author: zhaops
 * @time: 2018/9/18 16:33
 */
@Component
public class ProductServiceFacade extends ProductServiceServiceImpl {
    @Autowired
    private ServiceTokenFacade serviceTokenFacade;
    @Autowired
    private ServiceInfoFacade serviceInfoFacade;
    @Autowired
    private LantoneProductFacade lantoneProductFacade;
    @Autowired
    private OpenedProductsFacade openedProductsFacade;

    /**
     * 建立产品服务端关联并生成令牌
     *
     * @param productServiceSaveVO
     * @return
     */
    public ProductServiceDTO genProductService(ProductServiceSaveVO productServiceSaveVO) {
        ProductServiceDTO productServiceDTO = new ProductServiceDTO();
        Long operatorId = Long.parseLong(UserUtils.getCurrentPrincipleID());
        Long userId = null;
        if (null != productServiceSaveVO.getUserId()) {
            userId = productServiceSaveVO.getUserId();
        } else {
            userId = operatorId;
        }
        LantoneProduct lantoneProduct = lantoneProductFacade.getById(productServiceSaveVO.getProductId());
        if (lantoneProduct == null) {
            throw new CommonException(CommonErrorCode.NOT_EXISTS,
                    "产品未找到");
        } else if (lantoneProduct.getIsDeleted().equals(IsDeleteEnum.Y.getKey())) {
            throw new CommonException(CommonErrorCode.NOT_EXISTS,
                    "无法操作，该产品线已删除");
        } else if (lantoneProduct.getServiceStatus().equals(StatusEnum.Disable.getKey())) {
            throw new CommonException(CommonErrorCode.NOT_EXISTS,
                    "无法操作，该产品线已停用");
        }
        QueryWrapper<OpenedProducts> openedProductsQueryWrapper = new QueryWrapper<>();
        openedProductsQueryWrapper.eq("product_id", lantoneProduct.getId()).eq("user_id", userId);
        List<OpenedProducts> openedProductsList = openedProductsFacade.list(openedProductsQueryWrapper);
        openedProductsQueryWrapper.eq("is_deleted", IsDeleteEnum.N.getKey());
        OpenedProducts openedProducts = openedProductsFacade.getOne(openedProductsQueryWrapper);
        if (!productServiceSaveVO.getType().equals(TokenTypeEnum.Trial.getKey())) {
            if (openedProductsList.size() == 0) {
                throw new CommonException(CommonErrorCode.NOT_EXISTS,
                        "无法操作，该产品未开通");
            } else if (openedProducts == null) {
                throw new CommonException(CommonErrorCode.NOT_EXISTS,
                        "无法操作，该产品已删除");
            } else if (openedProducts.getServiceStatus().equals(StatusEnum.Disable.getKey())) {
                throw new CommonException(CommonErrorCode.NOT_EXISTS,
                        "无法操作，该产品已停用");
            } else if (openedProducts.getEndTime().before(new Date())) {
                throw new CommonException(CommonErrorCode.NOT_EXISTS,
                        "无法操作，该产品已到期");
            }
        }
        ServiceInfo serviceInfo = serviceInfoFacade.getById(productServiceSaveVO.getServiceId());
        if (serviceInfo == null || serviceInfo.getIsDeleted().equals(IsDeleteEnum.Y.getKey())) {
            throw new CommonException(CommonErrorCode.NOT_EXISTS,
                    "找不到服务端【" + serviceInfo.getName() + "】");
        } else if (serviceInfo.getUserId() != userId) {
            throw new CommonException(CommonErrorCode.SERVER_IS_ERROR,
                    "当前登录用户没有关联服务端【" + serviceInfo.getName() + "】");
        }

        QueryWrapper<ProductService> qwps = new QueryWrapper<>();
        qwps.eq("product_id", productServiceSaveVO.getProductId());
        qwps.eq("service_id", productServiceSaveVO.getServiceId());
        qwps.eq("is_deleted", IsDeleteEnum.N.getKey());
        ProductService productService = this.getOne(qwps);
        if (productService == null) {
            productService = new ProductService();
            productService.setProductId(productServiceSaveVO.getProductId());
            productService.setServiceId(productServiceSaveVO.getServiceId());
            productService.setCreator(operatorId.toString());
            productService.setGmtCreate(new Date());
            this.save(productService);
        } else {
            productService.setModifier(operatorId.toString());
            productService.setGmtModified(new Date());
            this.updateById(productService);
        }

        // 生成令牌
        // 如果已有令牌，先删除原令牌，再重新生成
        // 试用产品 type=3 需生成7天有效期，重新生成令牌，有效期继承，超出有效期不允许再生成令牌
        ServiceToken old_serviceToken = serviceTokenFacade.getByProductServiceId(productService.getId());
        //删除原有token
        if (old_serviceToken != null) {
            serviceTokenFacade.deleteByProductServiceId(old_serviceToken.getProductServiceId());
        }

        ServiceToken serviceToken = new ServiceToken();
        serviceToken.setCreator(operatorId.toString());
        serviceToken.setGmtCreate(new Date());
        serviceToken.setProductServiceId(productService.getId());
        serviceToken.setType(productServiceSaveVO.getType());
        serviceToken.setAppKeyId(GuidUtil.App_key());
        serviceToken.setAppKeySecret(GuidUtil.App_screct());
        serviceToken.setStatus(StatusEnum.Enable.getKey());
        if (old_serviceToken != null && old_serviceToken.getType().equals(TokenTypeEnum.Trial.getKey())) {
            //如果试用已过期，不允许再生成
            if (DateUtil.after(DateUtil.now(), old_serviceToken.getExpiringDate())) {
                throw new CommonException(CommonErrorCode.SERVER_IS_ERROR,
                        "当前试用账号已过期，不允许再生成令牌");
            }
            serviceToken.setStartingDate(old_serviceToken.getStartingDate());
            serviceToken.setExpiringDate(old_serviceToken.getExpiringDate());
        } else if (productServiceSaveVO.getType().equals(TokenTypeEnum.Trial.getKey())) {
            serviceToken.setStartingDate(new Date());
            serviceToken.setExpiringDate(DateUtil.addDay(serviceToken.getStartingDate(), 7));
        }
        serviceTokenFacade.save(serviceToken);
        productServiceDTO.setServiceToken(serviceToken);

        productServiceDTO.setProductId(productService.getProductId());
        productServiceDTO.setServiceId(productService.getServiceId());

        productServiceDTO.setServiceName(serviceInfo.getName());
        productServiceDTO.setServiceDescription(serviceInfo.getDescription());

        productServiceDTO.setProductName(lantoneProduct.getName());
        productServiceDTO.setProductDecription(lantoneProduct.getDecription());
        return productServiceDTO;
    }

    /**
     * 删除产品服务端关联，级联删除令牌
     *
     * @param productServiceId
     * @return
     */
    public Boolean deleteProductService(Long productServiceId) {
        ProductService productService = this.getById(productServiceId);
        if (productService == null || productService.getIsDeleted().equals(IsDeleteEnum.Y.getKey())) {
            throw new CommonException(CommonErrorCode.NOT_EXISTS, "找不到产品服务端");
        }
        //删除关联令牌
        serviceTokenFacade.deleteByProductServiceId(productService.getId());
        //删除产品服务端
        productService.setIsDeleted(IsDeleteEnum.Y.getKey());
        this.updateById(productService);
        return true;
    }

    /**
     * 删除产品后，级联删除产品服务端关联和令牌
     * @param productId
     * @return
     */
    public Boolean deleteByProductId(Long productId) {
        QueryWrapper<ProductService> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("product_id", productId).eq("is_deleted", IsDeleteEnum.N.getKey());
        List<ProductService> productServiceList = this.list(queryWrapper);
        Map<Long, ProductService> map = EntityUtil.makeEntityMap(productServiceList, "id");
        //删除令牌
        UpdateWrapper<ServiceToken> tokenUpdateWrapper = new UpdateWrapper<>();
        tokenUpdateWrapper.in("product_service_id", map.keySet());
        tokenUpdateWrapper.set("is_deleted", IsDeleteEnum.Y.getKey());
        serviceTokenFacade.update(new ServiceToken(), tokenUpdateWrapper);

        //删除产品服务端关联
        UpdateWrapper<ProductService> productServiceUpdateWrapper = new UpdateWrapper<>();
        productServiceUpdateWrapper.in("id", map.keySet());
        productServiceUpdateWrapper.set("is_deleted", IsDeleteEnum.Y.getKey());
        this.update(new ProductService(), productServiceUpdateWrapper);

        //删除系统自动生成的服务端
        Map<Long, List<ProductService>> serviceMap = EntityUtil.makeEntityListMap(productServiceList, "serviceId");
        UpdateWrapper<ServiceInfo> serviceInfoUpdateWrapper = new UpdateWrapper<>();
        serviceInfoUpdateWrapper.in("id", serviceMap.keySet())
                .eq("type", ServiceTypeEnum.Sys_Create.getKey())
                .eq("is_deleted", IsDeleteEnum.N.getKey())
                .set("is_deleted", IsDeleteEnum.Y.getKey());
        serviceInfoFacade.update(new ServiceInfo(), serviceInfoUpdateWrapper);
        return true;
    }


    /**
     * 获取当前用户产品服务关联列表
     *
     * @param page
     * @return
     */
    public IPage<ProductServiceWrapper> selectProductServiceByCurrentUserPage(Page<ProductServiceWrapper> page) {
        Long userId = Long.parseLong(UserUtils.getCurrentPrincipleID());
        ProductServiceWrapper productServiceVO = new ProductServiceWrapper();
        productServiceVO.setUserId(userId);
        IPage<ProductServiceWrapper> psPage = this.selectProductServicePage(page, productServiceVO);
        return psPage;
    }
}