package com.liquidnet.service.slime.service.impl;

import com.liquidnet.common.exception.LiquidnetServiceException;
import com.liquidnet.commons.lang.util.CollectionUtil;
import com.liquidnet.commons.lang.util.DateUtil;
import com.liquidnet.commons.lang.util.IDGenerator;
import com.liquidnet.commons.lang.util.StringUtil;
import com.liquidnet.service.base.ErrorMapping;
import com.liquidnet.service.base.SqlMapping;
import com.liquidnet.service.base.constant.MQConst;
import com.liquidnet.service.slime.constant.SlimeAuthorizationConst;
import com.liquidnet.service.slime.dto.param.SlimeAuthorizationPermissionParam;
import com.liquidnet.service.slime.dto.param.SlimeAuthorizationRecordParam;
import com.liquidnet.service.slime.dto.vo.SlimeAuthorizationPerformanceVo;
import com.liquidnet.service.slime.dto.vo.SlimeAuthorizationPermissionsVo;
import com.liquidnet.service.slime.dto.vo.SlimeAuthorizationRecordsVo;
import com.liquidnet.service.slime.service.ISlimeAuthorizationRecordsService;
import com.liquidnet.service.slime.service.SlimeMongoService;
import com.liquidnet.service.slime.util.QueueUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

@Slf4j
@Service
public class SlimeAuthorizationRecordsServiceImpl implements ISlimeAuthorizationRecordsService {

    @Autowired
    SlimeMongoService slimeMongoService;

    @Autowired
    MongoTemplate mongoTemplate;

    @Autowired
    QueueUtil queueUtil;

    @Override
    public SlimeAuthorizationPerformanceVo performanceAuthorization(String uid, String performanceId) {
        SlimeAuthorizationPerformanceVo authorizationPerformanceVo = slimeMongoService.getAuthorizationPerformanceVo(performanceId, uid);
        return authorizationPerformanceVo;
    }

    @Override
    public List<SlimeAuthorizationRecordsVo> performanceRecordCheckers(String cuid, String performanceId) {
        List<SlimeAuthorizationRecordsVo> authorizationRecordsVos = slimeMongoService.getAuthorizationRecordsCheckersVosByCuid(cuid, performanceId);

        if (!CollectionUtil.isEmpty(authorizationRecordsVos)) {
            for (SlimeAuthorizationRecordsVo recordsVo: authorizationRecordsVos) {
                if (null != recordsVo.getMobile() && recordsVo.getMobile().length() > 4) {
                    recordsVo.setMobile(StringUtil.hiddenMobile(recordsVo.getMobile()));
                }
            }
        }

        return authorizationRecordsVos;
    }

    @Override
    public String performanceRecordCheckerAdd(String cuid, SlimeAuthorizationRecordParam parameter) {
        LocalDateTime now = LocalDateTime.now();

        // 目前仅授权 验票 统计
        if (cuid.equals(parameter.getUid())) {
            // 不能授权自己权限
            ErrorMapping.ErrorMessage errorMessage = ErrorMapping.get("13304");
            throw new LiquidnetServiceException(errorMessage.getCode(), errorMessage.getMessage());
        }
        SlimeAuthorizationPermissionParam checkPermissionParam = null;
        SlimeAuthorizationPermissionParam salesPermissionParam = null;
        for (SlimeAuthorizationPermissionParam permissionParam: parameter.getPermissions()) {
            if (permissionParam.getPermissionId().equals(SlimeAuthorizationConst.PerformancePermission.CHECK.getId())) {
                checkPermissionParam = permissionParam;
            }
            if (permissionParam.getPermissionId().equals(SlimeAuthorizationConst.PerformancePermission.SALES.getId())) {
                salesPermissionParam = permissionParam;
            }
        }
        // 至少选择一个授权权限
        if (null == checkPermissionParam && null == salesPermissionParam) {
            ErrorMapping.ErrorMessage errorMessage = ErrorMapping.get("13305");
            throw new LiquidnetServiceException(errorMessage.getCode(), errorMessage.getMessage());
        }
        // 不能重复授权
        List<SlimeAuthorizationRecordsVo> authorizationRecordsVos = slimeMongoService.getAuthorizationRecordsCheckersVosByCuid(cuid, parameter.getPerformanceId());
        if (!CollectionUtil.isEmpty(authorizationRecordsVos)) {
            for (SlimeAuthorizationRecordsVo vo : authorizationRecordsVos) {
                if (vo.getUid().equals(parameter.getUid())) {
                    ErrorMapping.ErrorMessage errorMessage = ErrorMapping.get("13306");
                    throw new LiquidnetServiceException(errorMessage.getCode(), errorMessage.getMessage());
                }
            }
        }
        // 获取最大权限角色
        SlimeAuthorizationConst.PerformanceRole maxPerformanceRole = this.getMaxGrantPerformanceRole(cuid, parameter.getPerformanceId());
        if (null == maxPerformanceRole) {
            // 无授权权限
            ErrorMapping.ErrorMessage errorMessage = ErrorMapping.get("13301");
            throw new LiquidnetServiceException(errorMessage.getCode(), errorMessage.getMessage());
        }
        if (null != salesPermissionParam && (!maxPerformanceRole.equals(SlimeAuthorizationConst.PerformanceRole.CREATOR) && !maxPerformanceRole.equals(SlimeAuthorizationConst.PerformanceRole.SPONSOR))) {
            // 无权限授于统计权限
            ErrorMapping.ErrorMessage errorMessage = ErrorMapping.get("13302");
            throw new LiquidnetServiceException(errorMessage.getCode(), errorMessage.getMessage());
        }

        // 授权记录 vo
        SlimeAuthorizationRecordsVo authorizationRecordsVo = SlimeAuthorizationRecordsVo.getNew();
        authorizationRecordsVo.setAuthorizationRecordId(IDGenerator.nextSnowId());
        authorizationRecordsVo.setPerformanceId(parameter.getPerformanceId());
        authorizationRecordsVo.setUidRole(SlimeAuthorizationConst.PerformanceRole.CHECKER.getRole());
        authorizationRecordsVo.setUid(parameter.getUid());
        authorizationRecordsVo.setMobile(parameter.getMobile());
        authorizationRecordsVo.setName(parameter.getName());
        authorizationRecordsVo.setCuid(cuid);
        authorizationRecordsVo.setCuidRole(maxPerformanceRole.getRole());
        authorizationRecordsVo.setCreatedAt(now);

        // 授权权限 vos
        List<SlimeAuthorizationPermissionsVo> checkerAuthorizationPermissionsVos = new ArrayList<>();
        if (null != checkPermissionParam) {
            // 验票
            SlimeAuthorizationPermissionsVo authorizationPermissionsVo = SlimeAuthorizationPermissionsVo.getNew();
            authorizationPermissionsVo.setAuthorizationPermissionId(IDGenerator.nextSnowId());
            authorizationPermissionsVo.setAuthorizationRecordId(authorizationRecordsVo.getAuthorizationRecordId());
            authorizationPermissionsVo.setPermissionId(SlimeAuthorizationConst.PerformancePermission.CHECK.getId());
            authorizationPermissionsVo.setStartTime(now);
            authorizationPermissionsVo.setEndTime(now.plusYears(10));
            authorizationPermissionsVo.setCreatedAt(now);
            checkerAuthorizationPermissionsVos.add(authorizationPermissionsVo);
        }
        if (null != salesPermissionParam) {
            // 销售 及 查看时间范围
            LocalDateTime startTime = LocalDateTime.parse(salesPermissionParam.getStartTime(), DateTimeFormatter.ofPattern(DateUtil.DATE_FULL_STR));
            LocalDateTime endTime = LocalDateTime.parse(salesPermissionParam.getEndTime(), DateTimeFormatter.ofPattern(DateUtil.DATE_FULL_STR));
            if (!startTime.isBefore(endTime)) {
                ErrorMapping.ErrorMessage errorMessage = ErrorMapping.get("13303");
                throw new LiquidnetServiceException(errorMessage.getCode(), errorMessage.getMessage());
            }
            SlimeAuthorizationPermissionsVo authorizationPermissionsVo = SlimeAuthorizationPermissionsVo.getNew();
            authorizationPermissionsVo.setAuthorizationPermissionId(IDGenerator.nextSnowId());
            authorizationPermissionsVo.setAuthorizationRecordId(authorizationRecordsVo.getAuthorizationRecordId());
            authorizationPermissionsVo.setPermissionId(SlimeAuthorizationConst.PerformancePermission.SALES.getId());
            authorizationPermissionsVo.setStartTime(startTime);
            authorizationPermissionsVo.setEndTime(endTime);
            authorizationPermissionsVo.setCreatedAt(now);
            checkerAuthorizationPermissionsVos.add(authorizationPermissionsVo);
        }
        authorizationRecordsVo.setPermissionsVos(checkerAuthorizationPermissionsVos);

        // mongo
        long s = System.currentTimeMillis();
        mongoTemplate.insert(authorizationRecordsVo, SlimeAuthorizationRecordsVo.class.getSimpleName());
        log.debug("#MONGO耗时:{}ms", System.currentTimeMillis() - s);

        // 聚合角色及权限 vo mongo
        slimeMongoService.getAndSyncAuthorizationPerformanceVo(authorizationRecordsVo.getPerformanceId(), authorizationRecordsVo.getUid());

        // sql
        LinkedList<String> toMqSqls = CollectionUtil.linkedListString();
        LinkedList<Object[]> authorizationRecordsInsertObjs = CollectionUtil.linkedListObjectArr();
        LinkedList<Object[]> authorizationPermissionsInsertObjs = CollectionUtil.linkedListObjectArr();
        // 授权记录 sql
        toMqSqls.add(SqlMapping.get("slime_authorization_records.insert"));
        authorizationRecordsInsertObjs.add(new Object[]{
                authorizationRecordsVo.getAuthorizationRecordId(), authorizationRecordsVo.getPerformanceId(),
                authorizationRecordsVo.getUidRole(), authorizationRecordsVo.getUid(), authorizationRecordsVo.getMobile(), authorizationRecordsVo.getName(),
                authorizationRecordsVo.getCuidRole(), authorizationRecordsVo.getCuid(),
                authorizationRecordsVo.getCreatedAt()
        });
        // 授权权限 sql
        toMqSqls.add(SqlMapping.get("slime_authorization_permissions.insert"));
        for (SlimeAuthorizationPermissionsVo authorizationPermissionsVo  : checkerAuthorizationPermissionsVos) {
            authorizationPermissionsInsertObjs.add(new Object[]{
                    authorizationPermissionsVo.getAuthorizationPermissionId(), authorizationPermissionsVo.getAuthorizationRecordId(),
                    authorizationPermissionsVo.getPermissionId(), authorizationPermissionsVo.getStartTime(), authorizationPermissionsVo.getEndTime(),
                    authorizationPermissionsVo.getCreatedAt()
            });
        }

        // mq
        s = System.currentTimeMillis();
        queueUtil.sendMsgByRedis(
                MQConst.SlimeQueue.SQL_SLIME_FIELD.getKey(),
                SqlMapping.gets(toMqSqls, authorizationRecordsInsertObjs, authorizationPermissionsInsertObjs)
        );
        log.debug("#MQ耗时:{}ms", System.currentTimeMillis() - s);

        return authorizationRecordsVo.getAuthorizationRecordId();
    }

    @Override
    public void performanceRecordCheckerDel(String cuid, String authorizationRecordId) {
        LocalDateTime now = LocalDateTime.now();

        // 查询授权记录
        SlimeAuthorizationRecordsVo authorizationRecordsVo = slimeMongoService.getAuthorizationRecordsVoByAuthorizationRecordId(authorizationRecordId);
        if (null == authorizationRecordsVo || !authorizationRecordsVo.getCuid().equals(cuid) || !authorizationRecordsVo.getUidRole().equals(SlimeAuthorizationConst.PerformanceRole.CHECKER.getRole())) {
            // 无授权权限
            ErrorMapping.ErrorMessage errorMessage = ErrorMapping.get("13301");
            throw new LiquidnetServiceException(errorMessage.getCode(), errorMessage.getMessage());
        }

        // 授权记录 vo
        authorizationRecordsVo.setUpdatedAt(now);
        authorizationRecordsVo.setDeletedAt(now);

        // mongo
        long s = System.currentTimeMillis();
        mongoTemplate.remove(Query.query(Criteria.where("authorizationRecordId").is(authorizationRecordId)), SlimeAuthorizationRecordsVo.class.getSimpleName());
        log.debug("#MONGO耗时:{}ms", System.currentTimeMillis() - s);

        // 聚合角色及权限 vo mongo
        slimeMongoService.getAndSyncAuthorizationPerformanceVo(authorizationRecordsVo.getPerformanceId(), authorizationRecordsVo.getUid());

        // sql
        LinkedList<String> toMqSqls = CollectionUtil.linkedListString();
        LinkedList<Object[]> authorizationRecordsUpdateObjs = CollectionUtil.linkedListObjectArr();
        toMqSqls.add(SqlMapping.get("slime_authorization_records.update"));
        authorizationRecordsUpdateObjs.add(new Object[]{
                authorizationRecordsVo.getUpdatedAt(), authorizationRecordsVo.getDeletedAt(), authorizationRecordsVo.getAuthorizationRecordId()
        });

        // mq
        s = System.currentTimeMillis();
        queueUtil.sendMsgByRedis(
                MQConst.SlimeQueue.SQL_SLIME_FIELD.getKey(),
                SqlMapping.gets(toMqSqls, authorizationRecordsUpdateObjs)
        );
        log.debug("#MQ耗时:{}ms", System.currentTimeMillis() - s);
    }


    // 获取最大授权角色
    private SlimeAuthorizationConst.PerformanceRole getMaxGrantPerformanceRole(String uid, String performanceId) {
        SlimeAuthorizationPerformanceVo authorizationPerformanceVo = slimeMongoService.getAuthorizationPerformanceVo(performanceId, uid);
        if (null == authorizationPerformanceVo) {
            return null;
        }
        if (CollectionUtil.isEmpty(authorizationPerformanceVo.getUidRoles())) {
            return null;
        }

        SlimeAuthorizationConst.PerformanceRole maxRole = SlimeAuthorizationConst.PerformanceRole.valueOf(authorizationPerformanceVo.getUidRoles().get(0));
        for (String uidRole : authorizationPerformanceVo.getUidRoles()) {
            SlimeAuthorizationConst.PerformanceRole role = SlimeAuthorizationConst.PerformanceRole.valueOf(uidRole);
            if (!role.equals(SlimeAuthorizationConst.PerformanceRole.AUDITOR) && !role.equals(SlimeAuthorizationConst.PerformanceRole.CHECKER)) {
                if (role.getLevel() > maxRole.getLevel()) {
                    maxRole = role;
                }
            }
        }

        return maxRole;
    }
}
