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

import cn.hutool.core.util.StrUtil;
import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qiaoba.auth.utils.SecurityUtil;
import com.qiaoba.common.base.constants.BaseConstant;
import com.qiaoba.common.base.constants.TenantConstant;
import com.qiaoba.common.base.context.BaseContext;
import com.qiaoba.common.base.enums.BaseEnum;
import com.qiaoba.common.base.enums.DataBaseEnum;
import com.qiaoba.common.base.exceptions.ServiceException;
import com.qiaoba.common.database.config.DynamicDataSourceConfig;
import com.qiaoba.common.database.entity.PageQuery;
import com.qiaoba.common.database.entity.TableDataInfo;
import com.qiaoba.common.database.utils.JdbcUtil;
import com.qiaoba.common.redis.service.RedisService;
import com.qiaoba.module.tenant.entity.SysTenant;
import com.qiaoba.module.tenant.entity.SysTenantDatasource;
import com.qiaoba.module.tenant.entity.param.SysTenantParam;
import com.qiaoba.module.tenant.handler.DataHandlerFactory;
import com.qiaoba.module.tenant.mapper.SysTenantMapper;
import com.qiaoba.module.tenant.service.SysTenantDatasourceService;
import com.qiaoba.module.tenant.service.SysTenantService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

import java.sql.Connection;
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 SysTenantDatasourceService sysTenantDatasourceService;
    private final RedisService redisService;

    @Value("${spring.application.name}")
    private String baseDatabase;

    @Override
    public int insert(SysTenant sysTenant) {
        sysTenant.setCreateTime(new Date());
        sysTenant.setCreateUser(SecurityUtil.getLoginUsername());
        sysTenant.setStatus(BaseEnum.NORMAL.getCode());
        int result = sysTenantMapper.insert(sysTenant);
        if (result > BaseConstant.HANDLE_ERROR) {
            toCache(sysTenant);
        }
        return result;
    }

    @Override
    public int update(SysTenant sysTenant) {
        sysTenant.setUpdateTime(new Date());
        sysTenant.setUpdateUser(SecurityUtil.getLoginUsername());
        int result = sysTenantMapper.updateById(sysTenant);
        if (result > BaseConstant.HANDLE_ERROR) {
            toCache(sysTenant);
        }
        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 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 initData(String tenantId) throws Exception {

        SysTenant sysTenant = selectById(tenantId);
        if (Objects.isNull(sysTenant)) {
            throw new ServiceException("租户不存在");
        }
        // 初始化数据
        Connection connection = getConnection(sysTenant);
        boolean result = DataHandlerFactory.getHandler(connection.getMetaData().getDatabaseProductName().trim()).handle(connection, tenantId, !SysTenant.COLUMN_MODE.equals(sysTenant.getMode()));
        if (!result) {
            throw new ServiceException("同步数据出错, 数据已回滚");
        }
    }

    @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);
        }
    }

    private QueryWrapper<SysTenant> param2Wrapper(SysTenantParam param) {
        QueryWrapper<SysTenant> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(StrUtil.isNotBlank(param.getStatus()), SysTenant::getStatus, param.getStatus())
                .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和名字两个字段
        if (param.getIsLogin()) {
            wrapper.lambda()
                    .select(SysTenant::getCompanyName, SysTenant::getTenantId);
        }
        return wrapper;
    }

    private Connection getConnection(SysTenant sysTenant) {
        if (SysTenant.COLUMN_MODE.equals(sysTenant.getMode())) {
            return column();
        }
        if (SysTenant.SCHEMA_MODE.equals(sysTenant.getMode())) {
            return schema(sysTenant.getTenantId());
        }
        if (SysTenant.DATASOURCE_MODE.equals(sysTenant.getMode())) {
            return datasource(sysTenant.getTenantId());
        }

        throw new ServiceException("未找到租户设置的数据源模式");
    }

    /**
     * 处理字段模式
     */
    private Connection column() {
        DruidDataSource dataSource = DynamicDataSourceConfig.getPrimaryDataSource(TenantConstant.DEFAULT_TENANT_ID);
        return JdbcUtil.getConnection(dataSource.getDriverClassName(), dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword());
    }

    /**
     * 处理数据库模式
     */
    private Connection schema(String tenantId) {
        DruidDataSource dataSource = DynamicDataSourceConfig.getPrimaryDataSource(TenantConstant.DEFAULT_TENANT_ID);
        String realUrl = dataSource.getUrl().replaceFirst(baseDatabase, baseDatabase + BaseConstant.HYPHEN_JOIN_STR + tenantId);
        return JdbcUtil.getConnection(dataSource.getDriverClassName(), realUrl, dataSource.getUsername(), dataSource.getPassword());
    }

    /**
     * 处理数据源模式
     */
    private Connection datasource(String tenantId) {
        SysTenantDatasource primary = sysTenantDatasourceService.selectPrimary(tenantId);
        if (Objects.isNull(primary)) {
            throw new ServiceException("未找到租户主数据源信息");
        }
        return JdbcUtil.getConnection(DataBaseEnum.getDriver(primary.getType()), DataBaseEnum.getUrl(primary.getType(), primary.getIp(), primary.getPort(), primary.getName()), primary.getUsername(), primary.getPassword());
    }

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