package com.qmth.teachcloud.common.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qmth.boot.core.solar.config.SolarProperties;
import com.qmth.boot.core.solar.model.AppInfo;
import com.qmth.boot.core.solar.model.OrgInfo;
import com.qmth.boot.core.solar.service.SolarService;
import com.qmth.teachcloud.common.bean.result.AppInfoResult;
import com.qmth.teachcloud.common.contant.SpringContextHolder;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.BasicSchool;
import com.qmth.teachcloud.common.entity.SysOrg;
import com.qmth.teachcloud.common.entity.TSAuth;
import com.qmth.teachcloud.common.enums.AuthEnum;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import com.qmth.teachcloud.common.service.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.awt.*;
import java.util.*;
import java.util.List;

/**
 * @Description: 授权信息service
 * @Param:
 * @return:
 * @Author: wangliang
 * @Date: 2022/5/17
 */
@Service
public class AuthInfoServiceImpl implements AuthInfoService {
    private final static Logger log = LoggerFactory.getLogger(AuthInfoServiceImpl.class);

    @Resource
    SolarProperties solarProperties;

    @Resource
    SolarService solarService;

    @Resource
    TSAuthService tsAuthService;

    @Resource
    CommonCacheService commonCacheService;

    @Resource
    BasicSchoolService basicSchoolService;

    @Resource
    AuthInfoService authInfoService;

    @Resource
    SysOrgService sysOrgService;

    /**
     * 授权信息初始化
     *
     * @return
     */
    @Override
    public AppInfo appInfoInit() {
        AppInfo appInfo = null;
        try {
            appInfo = solarService.getAppInfo();
            if (Objects.nonNull(appInfo) && Objects.nonNull(solarProperties)) {
                if (Objects.nonNull(solarProperties.getAccessKey())
                        && !Objects.equals(solarProperties.getAccessKey().trim(), "")
                        && Objects.nonNull(solarProperties.getAccessSecret())
                        && !Objects.equals(solarProperties.getAccessSecret().trim(), "")) {//在线激活
//                    this.authError("不支持在线激活，请联系系统管理员！");
                    log.error("不支持在线激活，请联系系统管理员！");
                    licenseForDb(AuthEnum.OFF_LINE);
                } else if (Objects.nonNull(solarProperties.getLicense())
                        && !Objects.equals(solarProperties.getLicense().trim(), "")) {//离线激活
//                    this.authError("不支持离线激活，请联系系统管理员！");
                    log.error("不支持离线激活，请联系系统管理员！");
                    licenseForDb(AuthEnum.OFF_LINE);
                }
            } else {
                licenseForDb(AuthEnum.OFF_LINE);
            }
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
        }
        return appInfo;
    }

    /**
     * 授权信息初始化
     *
     * @param appInfo
     * @param accessKey
     * @param accessSecret
     * @return
     * @throws Exception
     */
    @Override
    public AppInfo appInfoInit(AppInfo appInfo, String accessKey, String accessSecret) throws Exception {
        authInfoService.saveAuthInfo(appInfo, AuthEnum.ON_LINE, null);
        return appInfo;
    }

    /**
     * app是否过期
     *
     * @param code
     * @return
     */
    @Override
    public void appHasExpired(String code) {
        BasicSchool basicSchool = commonCacheService.schoolCache(code);
        if ((Objects.nonNull(basicSchool) && Objects.nonNull(basicSchool.getEnable()) && !basicSchool.getEnable())
                || (Objects.isNull(solarService.getAppInfo()) || solarService.getAppInfo().getControl().hasExpired())
                || (Objects.isNull(solarService.getAppControl()) || solarService.getAppControl().hasExpired())) {
            throw ExceptionResultEnum.AUTH_INFO_ERROR.exception();
        }
    }

    /**
     * 离线激活
     *
     * @param licenseData
     */
    @Override
    public void updateLicense(byte[] licenseData) throws Exception {
        AppInfo appInfo = solarService.update(licenseData);
        if (Objects.isNull(appInfo)) {
            throw ExceptionResultEnum.ERROR.exception("激活失败");
        } else {
            authInfoService.saveAuthInfo(appInfo, AuthEnum.OFF_LINE, licenseData);
        }
    }

    /**
     * 查询授权信息
     *
     * @return
     */
    @Override
    public AppInfoResult selectAuthInfo() throws Exception {
        Long expireTime = null;
        AppInfo appInfo = solarService.getAppInfo();
        AuthEnum authEnum = AuthEnum.NON_ACTIVATED;
        String accessKey = null, accessSecret = null;
        if (Objects.isNull(appInfo)) {//说明未激活，从数据库取最后激活记录
            TSAuth tsAuth = licenseForDb(AuthEnum.OFF_LINE);
            if (Objects.nonNull(tsAuth)) {
                return new AppInfoResult(tsAuth.getExpireTime(), tsAuth.getAccessKey(), tsAuth.getAccessSecret(), tsAuth.getType());
            } else {
                return new AppInfoResult(expireTime, accessKey, accessSecret, authEnum);
            }
        } else {
            accessKey = solarProperties.getAccessKey();
            accessSecret = solarProperties.getAccessSecret();
            if (Objects.nonNull(appInfo) && Objects.nonNull(appInfo.getControl())) {
                expireTime = Objects.nonNull(appInfo.getControl().getExpireTime()) ? appInfo.getControl().getExpireTime() : -1;
            }
            if (Objects.nonNull(accessKey) && Objects.nonNull(accessSecret)) {
                authEnum = AuthEnum.ON_LINE;
            } else if (Objects.nonNull(expireTime)) {
                authEnum = AuthEnum.OFF_LINE;
            }
            return new AppInfoResult(expireTime, accessKey, accessSecret, authEnum);
        }
    }

    /**
     * 保存鉴权信息
     *
     * @param appInfo
     * @param authEnum
     * @param file
     * @throws Exception
     */
    @Override
    @Transactional
    public void saveAuthInfo(AppInfo appInfo, AuthEnum authEnum, byte[] file) throws Exception {
        List<OrgInfo> orgInfoList = solarService.getOrgList();
        List<TSAuth> tsAuthList = null;
        Map<String, String> orgCodesMap = null;
        Set<BasicSchool> basicSchoolSet = null;
        Set<SysOrg> sysOrgSet = null;
        if (!CollectionUtils.isEmpty(orgInfoList)) {
            tsAuthList = new ArrayList<>();
            basicSchoolSet = new HashSet<>();
            sysOrgSet = new HashSet<>();
            orgCodesMap = new HashMap<>();
        }

        Long expireTime = null;
        if (Objects.nonNull(appInfo) && Objects.nonNull(appInfo.getControl())) {
            expireTime = Objects.nonNull(appInfo.getControl().getExpireTime()) ? appInfo.getControl().getExpireTime() : -1;
        }
        for (OrgInfo o : orgInfoList) {
            orgCodesMap.put(o.getCode(), o.getCode());
            if (authEnum == AuthEnum.OFF_LINE) {
                if (Objects.isNull(file)) {
                    tsAuthList.add(new TSAuth(o.getId(), solarProperties.getLicense(), authEnum, expireTime));
                } else {
                    tsAuthList.add(new TSAuth(o.getId(), file, authEnum, expireTime));
                }
            } else {
                tsAuthList.add(new TSAuth(o.getId(), solarProperties.getAccessKey(), solarProperties.getAccessSecret(), authEnum, expireTime));
            }
            QueryWrapper<BasicSchool> basicSchoolQueryWrapper = new QueryWrapper<>();
            basicSchoolQueryWrapper.lambda().eq(BasicSchool::getCode, o.getCode());
            BasicSchool basicSchool = basicSchoolService.getOne(basicSchoolQueryWrapper);
            if (Objects.isNull(basicSchool)) {//不存在则创建学校
                basicSchool = new BasicSchool(o.getId(), o.getCode(), o.getName(), o.getAccessKey(), o.getAccessSecret());
                if (Objects.nonNull(o.getLogo()) && (!o.getLogo().startsWith("https:") || !o.getLogo().startsWith("http"))) {
                    basicSchool.setLogo("data:image/png;base64," + o.getLogo());
                } else {
                    basicSchool.setLogo(o.getLogoUrl());
                }
                basicSchoolSet.add(basicSchool);
            } else {
                basicSchool.setAccessKey(o.getAccessKey());
                basicSchool.setAccessSecret(o.getAccessSecret());
                basicSchool.setLogo(Objects.nonNull(o.getLogoUrl()) ? o.getLogoUrl() : basicSchool.getLogo());
                basicSchoolSet.add(basicSchool);
            }

            QueryWrapper<SysOrg> sysOrgQueryWrapper = new QueryWrapper<>();
            sysOrgQueryWrapper.lambda().eq(SysOrg::getSchoolId, basicSchool.getId());
            int count = sysOrgService.count(sysOrgQueryWrapper);
            if (count == 0) {
                sysOrgSet.add(new SysOrg(basicSchool.getId(), basicSchool.getName()));
            }
        }

        if (!CollectionUtils.isEmpty(tsAuthList) && !CollectionUtils.isEmpty(orgCodesMap)) {
            tsAuthService.remove(new QueryWrapper<TSAuth>().lambda().ge(TSAuth::getId, 0L));
            tsAuthService.saveOrUpdateBatch(tsAuthList);

            if (!CollectionUtils.isEmpty(basicSchoolSet)) {
                basicSchoolService.saveOrUpdateBatch(basicSchoolSet);
                commonCacheService.removeSchoolIdCache();
                commonCacheService.removeSchoolCodeCache();
            }

            AuthInfoService authInfoService = SpringContextHolder.getBean(AuthInfoService.class);
            authInfoService.updateSchoolEnable(orgCodesMap);

            if (!CollectionUtils.isEmpty(sysOrgSet)) {
                sysOrgService.saveOrUpdateBatch(sysOrgSet);
                commonCacheService.removeOrgCache();
            }
        }
    }

//    /**
//     * 激活失败
//     *
//     * @param message
//     */
//    protected void authError(String message) {
//        List<OrgInfo> orgInfoList = solarService.getOrgList();
//        if (!CollectionUtils.isEmpty(orgInfoList)) {
//            Map<Long, Long> orgIdsMap = orgInfoList.stream().collect(Collectors.toMap(m -> m.getId(), m -> m.getId()));
//            this.updateSchoolEnable(orgIdsMap);
//        }
//        throw ExceptionResultEnum.AUTH_INFO_ERROR.exception(message);
//    }

    /**
     * 更新学校启用/禁用
     *
     * @param orgCodesMap
     */
    @Override
    public void updateSchoolEnable(Map<String, String> orgCodesMap) {
        List<BasicSchool> basicSchoolList = basicSchoolService.list();
        if (!CollectionUtils.isEmpty(basicSchoolList)) {
            for (BasicSchool b : basicSchoolList) {
                if (orgCodesMap.containsKey(b.getCode())) {
                    b.setEnable(true);
                } else {
                    b.setEnable(false);
                }
            }
            basicSchoolService.saveOrUpdateBatch(basicSchoolList);
            commonCacheService.removeSchoolIdCache();
            commonCacheService.removeSchoolCodeCache();
        }
    }

    /**
     * 是否允许手机号登录
     *
     * @param schoolId 学校ID
     * @return
     */
    @Override
    public Boolean allowPhoneLogin(Long schoolId) {
        QueryWrapper<TSAuth> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(TSAuth::getSchoolId, schoolId);
        TSAuth tsAuth = tsAuthService.getOne(queryWrapper);
        return tsAuth != null && AuthEnum.ON_LINE.equals(tsAuth.getType());
    }

    /**
     * 强制从db更新激活信息
     *
     * @param authEnum
     * @throws Exception
     */
    public TSAuth licenseForDb(AuthEnum authEnum) throws Exception {
        TSAuth tsAuth = tsAuthService.lastAuthInfo(authEnum);
        if (Objects.nonNull(tsAuth)) {
            AppInfo appInfo = solarService.update(tsAuth.getFile());
            authInfoService.saveAuthInfo(appInfo, authEnum, tsAuth.getFile());
        } else {
            tsAuth = tsAuthService.lastAuthInfo(AuthEnum.ON_LINE);
            if (Objects.nonNull(tsAuth)) {
                AppInfo appInfo = solarService.update(tsAuth.getAccessKey(), tsAuth.getAccessSecret());
                authInfoService.saveAuthInfo(appInfo, AuthEnum.ON_LINE, null);
            }
        }
        return tsAuth;
    }
}
