package com.gxwebsoft.app.service.impl;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.app.entity.AppConfig;
import com.gxwebsoft.app.mapper.AppConfigMapper;
import com.gxwebsoft.app.param.AppConfigParam;
import com.gxwebsoft.app.service.AppConfigService;
import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.common.system.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 应用配置表 Service 实现类
 *
 * @author 科技小王子
 */
@Slf4j
@Service
public class AppConfigServiceImpl extends ServiceImpl<AppConfigMapper, AppConfig> implements AppConfigService {

    @Resource
    private UserService userService;

    /**
     * 配置加密密钥（从配置文件读取）
     */
    @Value("${app.config.encrypt-key:GXWebsoft2024!@#$}")
    private String encryptKey;

    /**
     * 分页查询应用配置
     */
    @Override
    public List<AppConfig> page(AppConfigParam param) {
        PageParam<AppConfig, AppConfigParam> page = new PageParam<>(param);
        page.setDefaultOrder("sort_number asc, config_id asc");
        List<AppConfig> list = baseMapper.selectPageRel(page, param);
        return page.sortRecords(list);
    }

    /**
     * 分页查询应用配置（返回PageResult）
     */
    public PageResult<AppConfig> pageRel(AppConfigParam param) {
        PageParam<AppConfig, AppConfigParam> page = new PageParam<>(param);
        page.setDefaultOrder("sort_number asc, config_id asc");
        List<AppConfig> list = baseMapper.selectPageRel(page, param);
        return new PageResult<>(list, page.getTotal());
    }

    /**
     * 获取应用配置列表
     */
    @Override
    public List<AppConfig> list(AppConfigParam param) {
        List<AppConfig> list = baseMapper.selectListRel(param);
        PageParam<AppConfig, AppConfigParam> page = new PageParam<>();
        page.setDefaultOrder("sort_number asc, config_id asc");
        return page.sortRecords(list);
    }

    /**
     * 根据应用ID获取配置映射（自动解密）
     */
    @Override
    public Map<String, Object> getConfigsByWebsiteId(Integer websiteId) {
        List<Map<String, Object>> configs = baseMapper.selectConfigsByWebsiteId(websiteId);
        Map<String, Object> result = new HashMap<>();

        for (Map<String, Object> config : configs) {
            String configKey = (String) config.get("configKey");
            Object configValue = config.get("configValue");
            Integer isEncrypted = (Integer) config.get("isEncrypted");

            // 解密
            if (isEncrypted != null && isEncrypted == 1 && configValue != null) {
                try {
                    configValue = decrypt((String) configValue);
                } catch (Exception e) {
                    log.error("配置解密失败: {}", configKey, e);
                }
            }

            result.put(configKey, configValue);
        }

        return result;
    }

    /**
     * 获取单个配置值
     */
    @Override
    public String getConfigValue(Integer websiteId, String configKey) {
        LambdaQueryWrapper<AppConfig> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AppConfig::getWebsiteId, websiteId);
        wrapper.eq(AppConfig::getConfigKey, configKey);
        AppConfig config = getOne(wrapper);

        if (config == null || config.getConfigValue() == null) {
            return null;
        }

        // 解密
        if (config.getIsEncrypted() != null && config.getIsEncrypted() == 1) {
            return decrypt(config.getConfigValue());
        }

        return config.getConfigValue();
    }

    /**
     * 保存配置
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveConfig(AppConfig config) {
        // 设置租户ID
        Integer tenantId = getCurrentTenantId();
        if (tenantId != null) {
            config.setTenantId(Long.valueOf(tenantId));
        }

        // 加密敏感信息
        if (config.getIsEncrypted() != null && config.getIsEncrypted() == 1 && config.getConfigValue() != null) {
            config.setConfigValue(encrypt(config.getConfigValue()));
        }

        save(config);
    }

    /**
     * 批量保存配置
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchSaveConfig(Integer websiteId, List<AppConfig> configs) {
        // 设置租户ID
        Integer tenantId = getCurrentTenantId();
        if (tenantId != null) {
            for (AppConfig config : configs) {
                config.setTenantId(Long.valueOf(tenantId));
            }
        }

        // 先删除该应用的所有配置
        remove(new LambdaQueryWrapper<AppConfig>()
                .eq(AppConfig::getWebsiteId, websiteId));

        // 批量插入新配置
        for (AppConfig config : configs) {
            config.setWebsiteId(websiteId);

            // 加密敏感信息
            if (config.getIsEncrypted() != null && config.getIsEncrypted() == 1 && config.getConfigValue() != null) {
                config.setConfigValue(encrypt(config.getConfigValue()));
            }

            save(config);
        }
    }

    /**
     * 更新配置
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateConfig(AppConfig config) {
        // 加密敏感信息
        if (config.getIsEncrypted() != null && config.getIsEncrypted() == 1 && config.getConfigValue() != null) {
            config.setConfigValue(encrypt(config.getConfigValue()));
        }

        updateById(config);
    }

    /**
     * 删除配置
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteConfig(Integer configId) {
        removeById(configId);
    }

    /**
     * 根据应用ID删除所有配置
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteByWebsiteId(Integer websiteId) {
        remove(new LambdaQueryWrapper<AppConfig>()
                .eq(AppConfig::getWebsiteId, websiteId));
    }

    /**
     * 构建查询条件
     */
    private LambdaQueryWrapper<AppConfig> buildQueryWrapper(AppConfigParam param) {
        LambdaQueryWrapper<AppConfig> wrapper = new LambdaQueryWrapper<>();

        if (param.getConfigId() != null) {
            wrapper.eq(AppConfig::getConfigId, param.getConfigId());
        }
        if (param.getWebsiteId() != null) {
            wrapper.eq(AppConfig::getWebsiteId, param.getWebsiteId());
        }
        if (param.getConfigKey() != null) {
            wrapper.like(AppConfig::getConfigKey, param.getConfigKey());
        }
        if (param.getConfigType() != null) {
            wrapper.eq(AppConfig::getConfigType, param.getConfigType());
        }
        if (param.getIsSecret() != null) {
            wrapper.eq(AppConfig::getIsSecret, param.getIsSecret());
        }

        wrapper.orderByAsc(AppConfig::getConfigType)
               .orderByAsc(AppConfig::getSortNumber)
               .orderByAsc(AppConfig::getConfigId);

        return wrapper;
    }

    /**
     * AES 加密
     */
    private String encrypt(String plainText) {
        AES aes = SecureUtil.aes(encryptKey.getBytes());
        return aes.encryptBase64(plainText);
    }

    /**
     * AES 解密
     */
    private String decrypt(String cipherText) {
        AES aes = SecureUtil.aes(encryptKey.getBytes());
        return aes.decryptStr(cipherText);
    }

    /**
     * 获取当前登录用户的租户ID
     */
    private Integer getCurrentTenantId() {
        try {
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            if (authentication != null && authentication.getPrincipal() instanceof User) {
                return ((User) authentication.getPrincipal()).getTenantId();
            }
        } catch (Exception e) {
            log.error("获取当前用户租户ID失败", e);
        }
        return null;
    }
}
