package com.usky.issue.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.usky.common.core.exception.BusinessException;
import com.usky.common.security.utils.SecurityUtils;
import com.usky.issue.domain.IssueCloudConfig;
import com.usky.issue.domain.IssueSyncStatus;
import com.usky.issue.domain.IssueSyncTask;
import com.usky.issue.domain.IssueTriggerEvent;
import com.usky.issue.mapper.IssueCloudConfigMapper;
import com.usky.issue.mapper.IssueSyncStatusMapper;
import com.usky.issue.mapper.IssueSyncTaskMapper;
import com.usky.issue.mapper.IssueTriggerEventMapper;
import com.usky.issue.service.CloudConfigService;
import com.usky.issue.service.CloudOperationLogService;
import com.usky.issue.service.client.CloudPlatformClient;
import com.usky.issue.service.constant.CloudIntegrationConstants;
import com.usky.issue.service.enums.SyncTypeEnum;
import com.usky.issue.service.enums.TaskStatusEnum;
import com.usky.issue.service.enums.TriggerEventCodeEnum;
import com.usky.issue.service.support.CloudEntitySupport;
import com.usky.issue.service.util.AesGcmCipher;
import com.usky.issue.service.util.CredentialMaskUtil;
import com.usky.issue.service.vo.CloudConfigResponse;
import com.usky.issue.service.vo.CloudConfigSaveRequest;
import com.usky.issue.service.vo.CloudConnectionTestRequest;
import com.usky.issue.service.vo.CloudConnectionTestResponse;
import com.usky.issue.service.vo.CloudConnectionTestResult;
import com.usky.issue.service.vo.CloudDisableResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;

/**
 * 云平台配置服务实现
 *
 * @author fyc
 * @date 2026-05-21
 */
@DS("usky-cloud")
@Slf4j
@Service
public class CloudConfigServiceImpl implements CloudConfigService {

    @Autowired
    private IssueCloudConfigMapper configMapper;
    @Autowired
    private IssueSyncStatusMapper syncStatusMapper;
    @Autowired
    private IssueTriggerEventMapper triggerEventMapper;
    @Autowired
    private IssueSyncTaskMapper syncTaskMapper;
    @Autowired
    private AesGcmCipher aesGcmCipher;
    @Autowired
    private CloudPlatformClient cloudPlatformClient;
    @Autowired
    private CloudOperationLogService operationLogService;

    @Override
    public CloudConfigResponse getConfig() {
        IssueCloudConfig config = findActiveConfig();
        if (config == null) {
            return null;
        }
        return toResponse(config);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CloudConfigResponse saveConfig(CloudConfigSaveRequest request) {
        Integer tenantId = SecurityUtils.getTenantId();
        String operator = CloudEntitySupport.resolveOperator();
        String requestIp = CloudEntitySupport.resolveRequestIp();

        if (!request.getTenantId().equals(tenantId)) {
            throw new BusinessException("输入租户ID与登录租户不一致，请确认后重试！");
        }

        IssueCloudConfig existing = findActiveConfig();
        if (existing == null) {
            IssueCloudConfig created = new IssueCloudConfig();
            created.setTenantId(request.getTenantId());
            created.setCredentialKey(aesGcmCipher.encrypt(request.getCredentialKey()));
            created.setStatus(1);
            created.setConnectionStatus(0);
            created.setVersion(1);
            CloudEntitySupport.fillOnInsert(created);
            configMapper.insert(created);
            initSyncStatusRows(created.getId(), created.getTenantId());
            initTriggerEvents(created.getId(), created.getTenantId());
            operationLogService.log(created.getId(), CloudIntegrationConstants.OPERATION_SAVE_CONFIG,
                    "新建配置 tenantId=" + request.getTenantId(), operator, requestIp);
            return toResponse(created);
        }
        Integer version = existing.getVersion();
        if (request.getVersion() != null && !request.getVersion().equals(version)) {
            throw new BusinessException("配置版本冲突，请刷新后重试");
        }
        existing.setTenantId(request.getTenantId());
        existing.setCredentialKey(aesGcmCipher.encrypt(request.getCredentialKey()));
        existing.setStatus(1);
        existing.setVersion(version + 1);
        CloudEntitySupport.fillOnUpdate(existing);
        int updated = configMapper.updateById(existing);
        if (updated == 0) {
            throw new BusinessException("配置版本冲突，请刷新后重试");
        }
        operationLogService.log(existing.getId(), CloudIntegrationConstants.OPERATION_SAVE_CONFIG,
                "更新配置 tenantId=" + CredentialMaskUtil.mask(String.valueOf(request.getTenantId())), operator, requestIp);
        return toResponse(configMapper.selectById(existing.getId()));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CloudConnectionTestResponse testConnection(CloudConnectionTestRequest request) {
        String operator = CloudEntitySupport.resolveOperator();
        String requestIp = CloudEntitySupport.resolveRequestIp();
        Integer tenantId = request.getTenantId();
        log.info("[连接测试] 开始 tenantId={}, cloudAddress={}, credentialKey={}",
                tenantId, request.getCloudAddress(), CredentialMaskUtil.mask(request.getCredentialKey()));

        Integer loginTenantId = SecurityUtils.getTenantId();
        if (loginTenantId != null && !tenantId.equals(loginTenantId)) {
            log.warn("[连接测试] 租户不一致 requestTenantId={}, loginTenantId={}", tenantId, loginTenantId);
            throw new BusinessException("输入租户ID与登录租户不一致，请确认后重试！");
        }

        IssueCloudConfig config = findConfigByTenantId(tenantId);
        if (config == null) {
            log.warn("[连接测试] 配置不存在 tenantId={}", tenantId);
            throw new BusinessException("云平台配置不存在，请先保存配置");
        }
        if (config.getStatus() != null && config.getStatus() == 0) {
            log.warn("[连接测试] 集成已禁用 tenantId={}, configId={}", tenantId, config.getId());
            throw new BusinessException("云平台集成已禁用");
        }
        validateCredentialKey(config, request.getCredentialKey());
        log.info("[连接测试] 本地密钥校验通过 configId={}", config.getId());

        CloudConnectionTestResult result = cloudPlatformClient.testConnection(
                request.getCloudAddress(), request.getTenantId(), request.getCredentialKey(),
                CloudEntitySupport.resolveAccessToken());

        log.info("[连接测试] 远程结果 success={}, networkReachable={}, authValid={}, tenantExists={}, message={}, costTime={}ms",
                result.isSuccess(), result.isNetworkReachable(), result.isAuthValid(),
                result.isTenantExists(), result.getMessage(), result.getCostTime());

        config.setConnectionStatus(result.isSuccess() ? 1 : 2);
        config.setLastTestTime(LocalDateTime.now());
        CloudEntitySupport.fillOnUpdate(config);
        configMapper.updateById(config);
        operationLogService.log(config.getId(), CloudIntegrationConstants.OPERATION_TEST_CONNECTION,
                "连接测试" + (result.isSuccess() ? "成功" : "失败") + "：" + result.getMessage(), operator, requestIp);
        return toConnectionTestResponse(result);
    }

    private void validateCredentialKey(IssueCloudConfig config, String requestKey) {
        try {
            String storedKey = aesGcmCipher.decrypt(config.getCredentialKey());
            if (!storedKey.equals(requestKey)) {
                log.warn("[连接测试] 密钥不一致 tenantId={}, configId={}, requestKey={}, storedKey={}",
                        config.getTenantId(), config.getId(),
                        CredentialMaskUtil.mask(requestKey), CredentialMaskUtil.mask(storedKey));
                throw new BusinessException("凭证密钥与已保存配置不一致");
            }
        } catch (BusinessException ex) {
            throw ex;
        } catch (Exception ex) {
            log.error("[连接测试] 密钥解密失败 tenantId={}, configId={}", config.getTenantId(), config.getId(), ex);
            throw new BusinessException("凭证密钥校验失败");
        }
    }

    @Override
    public CloudConnectionTestResponse validateTenantConnection(Integer tenantId) {
        CloudConnectionTestResponse response = new CloudConnectionTestResponse();
        if (tenantId == null) {
            log.warn("[连接测试-租户校验] tenantId 为空");
            response.setSuccess(false);
            response.setConnectionStatus(2);
            response.setMessage("租户ID不能为空");
            response.setNetworkReachable(true);
            response.setAuthValid(false);
            response.setTenantExists(false);
            return response;
        }

        IssueCloudConfig config = findConfigByTenantId(tenantId);
        if (config == null) {
            log.warn("[连接测试-租户校验] 配置不存在 tenantId={}", tenantId);
            response.setSuccess(false);
            response.setConnectionStatus(2);
            response.setMessage(CloudIntegrationConstants.MSG_TENANT_CONFIG_MISSING);
            response.setNetworkReachable(true);
            response.setAuthValid(true);
            response.setTenantExists(false);
            return response;
        }
        if (config.getStatus() != null && config.getStatus() == 0) {
            log.warn("[连接测试-租户校验] 配置已禁用 tenantId={}, configId={}", tenantId, config.getId());
            response.setSuccess(false);
            response.setConnectionStatus(2);
            response.setMessage("租户配置已禁用");
            response.setNetworkReachable(true);
            response.setAuthValid(true);
            response.setTenantExists(false);
            return response;
        }

        response.setSuccess(true);
        response.setConnectionStatus(1);
        response.setMessage(CloudIntegrationConstants.MSG_CONNECTION_SUCCESS);
        response.setNetworkReachable(true);
        response.setAuthValid(true);
        response.setTenantExists(true);
        log.info("[连接测试-租户校验] 通过 tenantId={}, configId={}", tenantId, config.getId());
        return response;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CloudDisableResponse disable(Integer status) {
        if (status == null || (status != 0 && status != 1)) {
            throw new BusinessException("status 只能为 0（禁用）或 1（启用）");
        }
        String operator = CloudEntitySupport.resolveOperator();
        String requestIp = CloudEntitySupport.resolveRequestIp();
        IssueCloudConfig config = requireConfig();

        int affected = 0;
        config.setStatus(status);
        CloudEntitySupport.fillOnUpdate(config);
        configMapper.updateById(config);

        if (status == 0) {
            affected = cancelRunningTasks(config.getId());
            operationLogService.log(config.getId(), CloudIntegrationConstants.OPERATION_DISABLE,
                    "禁用集成，终止任务数=" + affected, operator, requestIp);
        } else {
            operationLogService.log(config.getId(), CloudIntegrationConstants.OPERATION_ENABLE,
                    "启用集成", operator, requestIp);
        }

        CloudDisableResponse response = new CloudDisableResponse();
        response.setDisabled(status == 0);
        response.setAffectedTasks(affected);
        return response;
    }

    private IssueCloudConfig requireConfig() {
        IssueCloudConfig config = findActiveConfig();
        if (config == null) {
            throw new BusinessException("云平台配置不存在，请先保存配置");
        }
        return config;
    }

    @Override
    public IssueCloudConfig requireActiveConfig() {
        IssueCloudConfig config = findActiveConfig();
        if (config == null) {
            throw new BusinessException("云平台配置不存在，请先保存配置");
        }
        if (config.getStatus() != null && config.getStatus() == 0) {
            throw new BusinessException("云平台集成已禁用");
        }
        return config;
    }

    private IssueCloudConfig findActiveConfig() {
        return findConfigByTenantId(SecurityUtils.getTenantId());
    }

    private IssueCloudConfig findConfigByTenantId(Integer tenantId) {
        if (tenantId == null) {
            return null;
        }
        return configMapper.selectOne(new QueryWrapper<IssueCloudConfig>()
                .eq("is_deleted", 0)
                .eq("tenant_id", tenantId)
                .orderByDesc("id")
                .last("LIMIT 1"));
    }

    private CloudConnectionTestResponse toConnectionTestResponse(CloudConnectionTestResult result) {
        CloudConnectionTestResponse response = new CloudConnectionTestResponse();
        response.setSuccess(result.isSuccess());
        response.setConnectionStatus(result.isSuccess() ? 1 : 2);
        response.setMessage(result.getMessage());
        response.setNetworkReachable(result.isNetworkReachable());
        response.setAuthValid(result.isAuthValid());
        response.setTenantExists(result.isTenantExists());
        response.setCostTime(result.getCostTime());
        return response;
    }

    private int cancelRunningTasks(Long configId) {
        List<IssueSyncTask> running = syncTaskMapper.selectList(new QueryWrapper<IssueSyncTask>()
                .eq("config_id", configId)
                .eq("is_deleted", 0)
                .in("task_status",
                        TaskStatusEnum.PENDING.getCode(), TaskStatusEnum.RUNNING.getCode()));
        for (IssueSyncTask task : running) {
            task.setTaskStatus(TaskStatusEnum.CANCELLED.getCode());
            task.setFinishTime(LocalDateTime.now());
            task.setErrorSummary("集成已禁用，任务终止");
            CloudEntitySupport.fillOnUpdate(task);
            syncTaskMapper.updateById(task);
        }
        return running.size();
    }

    private void initSyncStatusRows(Long configId, Integer tenantId) {
        for (SyncTypeEnum type : SyncTypeEnum.values()) {
            IssueSyncStatus row = new IssueSyncStatus();
            row.setConfigId(configId);
            row.setTenantId(tenantId);
            row.setSyncType(type.getCode());
            row.setTypeName(type.getLabel());
            row.setTotalCount(0);
            row.setSuccessCount(0);
            row.setFailureCount(0);
            row.setUnsyncedCount(0);
            CloudEntitySupport.fillOnInsert(row);
            syncStatusMapper.insert(row);
        }
    }

    private void initTriggerEvents(Long configId, Integer tenantId) {
        Arrays.stream(TriggerEventCodeEnum.values()).forEach(code -> {
            IssueTriggerEvent event = new IssueTriggerEvent();
            event.setConfigId(configId);
            event.setTenantId(tenantId);
            event.setEventCode(code.getCode());
            event.setEventName(code.getName());
            event.setDescription(code.getDescription());
            event.setEnabled(0);
            CloudEntitySupport.fillOnInsert(event);
            triggerEventMapper.insert(event);
        });
    }

    private CloudConfigResponse toResponse(IssueCloudConfig config) {
        CloudConfigResponse resp = new CloudConfigResponse();
        resp.setId(config.getId());
        resp.setTenantId(String.valueOf(config.getTenantId()));
        try {
            resp.setCredentialKey(aesGcmCipher.decrypt(config.getCredentialKey()));
        } catch (Exception e) {
            resp.setCredentialKey(null);
        }
        resp.setStatus(config.getStatus());
        resp.setConnectionStatus(config.getConnectionStatus());
        resp.setVersion(config.getVersion());
        resp.setLastTestTime(config.getLastTestTime());
        resp.setUpdatedTime(config.getUpdatedTime());
        resp.setUpdatedBy(config.getUpdatedBy());
        resp.setCreatedTime(config.getCreatedTime());
        resp.setCreatedBy(config.getCreatedBy());
        resp.setCloudAddress(config.getCloudAddress());
        return resp;
    }
}
