package com.qiaoba.module.tenant.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qiaoba.api.tenant.entity.SysTenant;
import com.qiaoba.api.tenant.entity.dto.SysTenantDto;
import com.qiaoba.api.tenant.entity.param.SysTenantParam;
import com.qiaoba.api.tenant.service.SysTenantApiService;
import com.qiaoba.api.auth.utils.SecurityUtil;
import com.qiaoba.common.base.code.TenantErrorCode;
import com.qiaoba.common.base.constant.BaseConstant;
import com.qiaoba.common.base.constant.TenantConstant;
import com.qiaoba.common.base.context.BaseContext;
import com.qiaoba.common.base.enums.BaseEnum;
import com.qiaoba.common.base.exception.ServiceException;
import com.qiaoba.common.database.entity.PageQuery;
import com.qiaoba.common.database.entity.TableDataInfo;
import com.qiaoba.common.redis.service.RedisService;
import com.qiaoba.module.tenant.entity.dto.TenantSettingDto;
import com.qiaoba.module.tenant.mapper.SysTenantMapper;
import com.qiaoba.module.tenant.service.SysTenantService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;

import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * 租户管理 服务层实现
 *
 * @author ailanyin
 * @version 1.0
 * @since 2023/5/30 10:55
 */
@Configuration
@RequiredArgsConstructor
@Slf4j
public class SysTenantServiceImpl implements SysTenantService {


    private final SysTenantMapper sysTenantMapper;
    private final RedisService redisService;

    @Override
    public int insert(SysTenantDto dto) {
        SysTenant sysTenant = BeanUtil.copyProperties(dto, SysTenant.class);
        checkCompanyNameIsExist(sysTenant);
        sysTenant.setCreateTime(new Date());
        sysTenant.setCreateUser(SecurityUtil.getLoginUsername());
        sysTenant.setStatus(BaseEnum.NORMAL.getCode());
        sysTenant.setInitialized(BaseEnum.NO.getCode());
        int result = sysTenantMapper.insert(sysTenant);
        if (result > BaseConstant.HANDLE_ERROR) {
            toCache(sysTenant);
        }
        return result;
    }

    @Override
    public int update(SysTenantDto dto) {
        SysTenant oldTenant = selectById(dto.getTenantId());
        if (BaseEnum.ABNORMAL.getCode().equals(oldTenant.getStatus())) {
            throw new ServiceException(TenantErrorCode.DISABLE.getCode(), TenantErrorCode.DISABLE.getMsg());
        }
        SysTenant sysTenant = BeanUtil.copyProperties(dto, SysTenant.class);
        checkCompanyNameIsExist(sysTenant);
        if (DateUtil.compare(sysTenant.getExpireTime(), new Date()) > 0) {
            sysTenant.setStatus(BaseEnum.NORMAL.getCode());
        }
        sysTenant.setUpdateTime(new Date());
        sysTenant.setUpdateUser(SecurityUtil.getLoginUsername());
        int result = sysTenantMapper.updateById(sysTenant);
        if (result > BaseConstant.HANDLE_ERROR) {
            toCache(selectById(sysTenant.getTenantId()));
        }
        return result;
    }

    @Override
    public TableDataInfo<SysTenant> selectPageList(SysTenantParam param, PageQuery pageQuery) {
        return TableDataInfo.build(sysTenantMapper.selectPage(pageQuery.build(), param2Wrapper(param)));
    }

    @Override
    public SysTenant selectById(String tenantId) {
        return sysTenantMapper.selectById(tenantId);
    }

    @Override
    public SysTenant selectById(String tenantId, Boolean allowNull) {
        SysTenant sysTenant = selectById(tenantId);
        if (!allowNull) {
            if (Objects.isNull(sysTenant)) {
                throw new ServiceException(TenantErrorCode.NOT_FIND.getCode(), TenantErrorCode.NOT_FIND.getMsg());
            }
        }
        return sysTenant;
    }

    @Override
    public SysTenant selectFromCache(String tenantId) {
        BaseContext.setTenantId(TenantConstant.DEFAULT_TENANT_ID);
        SysTenant sysTenant = redisService.getObject(TenantConstant.TENANT_INFO_KEY_PREFIX + tenantId, SysTenant.class);
        BaseContext.clearTenantId();
        return sysTenant;
    }


    @Override
    public void updateStatus(String tenantId, String status) {
        sysTenantMapper.updateById(new SysTenant(tenantId, status));
        toCache(selectById(tenantId));
    }

    @Override
    public void resetCache() {
        List<SysTenant> sysTenants = sysTenantMapper.selectList(param2Wrapper(new SysTenantParam()));
        for (SysTenant sysTenant : sysTenants) {
            toCache(sysTenant);
        }
    }

    @Override
    public int updateMode(TenantSettingDto dto) {
        SysTenant sysTenant = BeanUtil.copyProperties(dto, SysTenant.class);
        int result = sysTenantMapper.updateById(sysTenant);
        if (result > BaseConstant.HANDLE_ERROR) {
            toCache(selectById(sysTenant.getTenantId()));
        }
        return result;
    }

    @Override
    public int initCompleted(String tenantId) {
        SysTenant sysTenant = new SysTenant();
        sysTenant.setTenantId(tenantId);
        sysTenant.setInitialized(BaseEnum.YES.getCode());
        int result = sysTenantMapper.updateById(sysTenant);
        if (result > BaseConstant.HANDLE_ERROR) {
            toCache(selectById(sysTenant.getTenantId()));
        }
        return result;
    }

    private QueryWrapper<SysTenant> param2Wrapper(SysTenantParam param) {
        QueryWrapper<SysTenant> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(StrUtil.isNotBlank(param.getStatus()), SysTenant::getStatus, param.getStatus())
                .eq(StrUtil.isNotBlank(param.getInitialized()), SysTenant::getInitialized, param.getInitialized())
                .like(StrUtil.isNotBlank(param.getCompanyName()), SysTenant::getCompanyName, param.getCompanyName())
                .like(StrUtil.isNotBlank(param.getContactName()), SysTenant::getContactName, param.getContactName());

        // 查未过期
        if (SysTenantParam.TYPE_NOT_EXPIRED.equals(param.getType())) {
            wrapper.lambda().ge(Objects.nonNull(param.getTime()), SysTenant::getExpireTime, param.getTime());
        }
        // 查已过期
        else {
            wrapper.lambda().lt(Objects.nonNull(param.getTime()), SysTenant::getExpireTime, param.getTime());
        }

        // 登录接口, 只返回 ID/Name/Mode
        if (param.getIsLogin()) {
            wrapper.lambda()
                    .select(SysTenant::getCompanyName, SysTenant::getTenantId, SysTenant::getMode);
        }
        return wrapper;
    }

    private void toCache(SysTenant sysTenant) {
        log.debug("加载租户信息进缓存, 租户ID: {}", sysTenant.getTenantId());
        redisService.set(TenantConstant.TENANT_INFO_KEY_PREFIX + sysTenant.getTenantId(), sysTenant);
    }

    private void checkCompanyNameIsExist(SysTenant sysTenant) {
        String companyName = sysTenantMapper.checkCompanyNameIsExist(sysTenant);
        if (StrUtil.isNotBlank(companyName)) {
            throw new ServiceException(TenantErrorCode.TENANT_NAME_EXIST.getCode(), TenantErrorCode.TENANT_NAME_EXIST.getMsg());
        }
    }

    @Override
    public List<SysTenant> selectList(SysTenantParam param) {
        return sysTenantMapper.selectList(param2Wrapper(param));
    }
}
