package com.liquidnet.service.merchant.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.merchant.constant.MerchantAuthorizationConst;
import com.liquidnet.service.merchant.dto.param.MerchantAuthorizationPermissionParam;
import com.liquidnet.service.merchant.dto.param.MerchantAuthorizationRecordParam;
import com.liquidnet.service.merchant.dto.vo.MerchantAuthorizationPerformanceVo;
import com.liquidnet.service.merchant.dto.vo.MerchantAuthorizationPermissionsVo;
import com.liquidnet.service.merchant.dto.vo.MerchantAuthorizationRecordsVo;
import com.liquidnet.service.merchant.service.IMerchantAuthorizationRecordsService;
import com.liquidnet.service.merchant.service.MerchantMongoService;
import com.liquidnet.service.merchant.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 MerchantAuthorizationRecordsServiceImpl implements IMerchantAuthorizationRecordsService {

    @Autowired
    MerchantMongoService merchantMongoService;

    @Autowired
    MongoTemplate mongoTemplate;

    @Autowired
    QueueUtil queueUtil;

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

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

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

        return authorizationRecordsVos;
    }

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

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

        // 授权记录 vo
        MerchantAuthorizationRecordsVo authorizationRecordsVo = MerchantAuthorizationRecordsVo.getNew();
        authorizationRecordsVo.setAuthorizationRecordId(IDGenerator.nextSnowId());
        authorizationRecordsVo.setPerformanceId(parameter.getPerformanceId());
        authorizationRecordsVo.setUidRole(MerchantAuthorizationConst.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<MerchantAuthorizationPermissionsVo> checkerAuthorizationPermissionsVos = new ArrayList<>();
        if (null != checkPermissionParam) {
            // 验票
            MerchantAuthorizationPermissionsVo authorizationPermissionsVo = MerchantAuthorizationPermissionsVo.getNew();
            authorizationPermissionsVo.setAuthorizationPermissionId(IDGenerator.nextSnowId());
            authorizationPermissionsVo.setAuthorizationRecordId(authorizationRecordsVo.getAuthorizationRecordId());
            authorizationPermissionsVo.setPermissionId(MerchantAuthorizationConst.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());
            }
            MerchantAuthorizationPermissionsVo authorizationPermissionsVo = MerchantAuthorizationPermissionsVo.getNew();
            authorizationPermissionsVo.setAuthorizationPermissionId(IDGenerator.nextSnowId());
            authorizationPermissionsVo.setAuthorizationRecordId(authorizationRecordsVo.getAuthorizationRecordId());
            authorizationPermissionsVo.setPermissionId(MerchantAuthorizationConst.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, MerchantAuthorizationRecordsVo.class.getSimpleName());
        log.debug("#MONGO耗时:{}ms", System.currentTimeMillis() - s);

        // 聚合角色及权限 vo mongo
        merchantMongoService.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("merchant_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("merchant_authorization_permissions.insert"));
        for (MerchantAuthorizationPermissionsVo 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.MerchantQueue.SQL_MERCHANT_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();

        // 查询授权记录
        MerchantAuthorizationRecordsVo authorizationRecordsVo = merchantMongoService.getAuthorizationRecordsVoByAuthorizationRecordId(authorizationRecordId);
        if (null == authorizationRecordsVo || !authorizationRecordsVo.getCuid().equals(cuid) || !authorizationRecordsVo.getUidRole().equals(MerchantAuthorizationConst.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)), MerchantAuthorizationRecordsVo.class.getSimpleName());
        log.debug("#MONGO耗时:{}ms", System.currentTimeMillis() - s);

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

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

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


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

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

        return maxRole;
    }
}
