package com.usky.issue.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.usky.issue.domain.IssueSyncDetail;
import com.usky.issue.domain.IssueSyncStatus;
import com.usky.issue.domain.IssueSyncTask;
import com.usky.issue.mapper.IssueSyncDetailMapper;
import com.usky.issue.mapper.IssueSyncStatusMapper;
import com.usky.issue.mapper.IssueSyncTaskMapper;
import com.usky.issue.service.CloudSyncTaskRunner;
import com.usky.issue.service.LocalSyncAgent;
import com.usky.issue.service.constant.CloudIntegrationConstants;
import com.usky.issue.service.enums.SyncDirection;
import com.usky.issue.service.enums.SyncTypeEnum;
import com.usky.issue.service.enums.TaskStatusEnum;
import com.usky.issue.service.support.CloudEntitySupport;
import com.usky.common.redis.core.RedisHelper;
import com.usky.issue.service.vo.SyncResult;
import org.springframework.beans.factory.annotation.Autowired;
import com.usky.issue.domain.IssueCloudConfig;
import com.usky.issue.mapper.IssueCloudConfigMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

/**
 * 同步任务执行器实现
 *
 * @author fyc
 * @date 2026-05-21
 */
@Service
public class CloudSyncTaskRunnerImpl implements CloudSyncTaskRunner {

    @Autowired
    private IssueSyncTaskMapper syncTaskMapper;
    @Autowired
    private IssueSyncDetailMapper syncDetailMapper;
    @Autowired
    private IssueSyncStatusMapper syncStatusMapper;
    @Autowired
    private IssueCloudConfigMapper configMapper;
    @Autowired
    private LocalSyncAgent localSyncAgent;
    @Autowired
    private RedisHelper redisHelper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public IssueSyncTask createTask(Long configId, SyncTypeEnum type, String triggerMode, SyncDirection direction) {
        IssueCloudConfig config = configMapper.selectById(configId);
        int pending = localSyncAgent.countPending(type, config, direction);
        IssueSyncTask task = new IssueSyncTask();
        task.setConfigId(configId);
        if (config != null) {
            task.setTenantId(config.getTenantId());
        }
        task.setSyncType(type.getCode());
        task.setTaskStatus(TaskStatusEnum.PENDING.getCode());
        task.setTriggerMode(triggerMode);
        task.setTotalCount(pending);
        task.setProcessedCount(0);
        task.setSuccessCount(0);
        task.setFailureCount(0);
        CloudEntitySupport.fillOnInsert(task);
        syncTaskMapper.insert(task);
        return task;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void executeSyncTask(Long taskId, SyncTypeEnum type, SyncDirection direction) {
        IssueSyncTask task = syncTaskMapper.selectById(taskId);
        if (task == null) {
            return;
        }
        if (TaskStatusEnum.CANCELLED.getCode().equals(task.getTaskStatus())) {
            return;
        }
        task.setTaskStatus(TaskStatusEnum.RUNNING.getCode());
        task.setStartTime(LocalDateTime.now());
        CloudEntitySupport.fillOnUpdate(task);
        syncTaskMapper.updateById(task);

        IssueCloudConfig config = configMapper.selectById(task.getConfigId());
        boolean fullSync = "MANUAL".equals(task.getTriggerMode()) && direction == SyncDirection.DOWN;
        SyncResult syncResult = localSyncAgent.executeSync(type, config, direction, fullSync);

        IssueSyncTask current = syncTaskMapper.selectById(taskId);
        if (current != null && TaskStatusEnum.CANCELLED.getCode().equals(current.getTaskStatus())) {
            return;
        }

        int total = Math.max(task.getTotalCount() == null ? 0 : task.getTotalCount(), syncResult.getTotalCount());
        task.setTotalCount(total);
        task.setProcessedCount(syncResult.getTotalCount());
        task.setSuccessCount(syncResult.getSuccessCount());
        task.setFailureCount(syncResult.getFailureCount());

        if (syncResult.getFailureCount() > 0 && syncResult.getSuccessCount() == 0) {
            task.setTaskStatus(TaskStatusEnum.FAILED.getCode());
            task.setErrorSummary(syncResult.getErrorMessage() != null
                    ? syncResult.getErrorMessage()
                    : "同步失败: " + syncResult.getFailureCount() + " 条");
        } else if (syncResult.getTotalCount() == 0) {
            task.setTaskStatus(TaskStatusEnum.SUCCESS.getCode());
            task.setErrorSummary(syncResult.getErrorMessage() != null
                    ? syncResult.getErrorMessage()
                    : CloudIntegrationConstants.MSG_NO_SYNC_DATA);
        } else {
            task.setTaskStatus(TaskStatusEnum.SUCCESS.getCode());
            if (syncResult.getFailureCount() > 0) {
                task.setErrorSummary(syncResult.getErrorMessage() != null
                        ? syncResult.getErrorMessage()
                        : "部分失败: " + syncResult.getFailureCount() + " 条");
            }
        }

        task.setFinishTime(LocalDateTime.now());
        CloudEntitySupport.fillOnUpdate(task);
        syncTaskMapper.updateById(task);

        recordSyncDetails(taskId, task.getTenantId(), syncResult);
        refreshSyncStatus(task.getConfigId(), type, task);
        redisHelper.delete(CloudIntegrationConstants.CACHE_STATUS_PREFIX + task.getConfigId());
    }

    private void recordSyncDetails(Long taskId, Integer tenantId, SyncResult syncResult) {
        if (syncResult.getTotalCount() <= 0) {
            return;
        }
        IssueSyncDetail detail = new IssueSyncDetail();
        detail.setTaskId(taskId);
        detail.setTenantId(tenantId);
        detail.setDataId("batch-" + taskId);
        detail.setRetryCount(0);
        detail.setDetailStatus(syncResult.getFailureCount() > 0
                ? TaskStatusEnum.FAILED.getCode() : TaskStatusEnum.SUCCESS.getCode());
        if (syncResult.getFailureCount() > 0) {
            detail.setErrorMessage(syncResult.getErrorMessage());
        }
        CloudEntitySupport.fillOnInsert(detail);
        syncDetailMapper.insert(detail);
    }

    private void refreshSyncStatus(Long configId, SyncTypeEnum type, IssueSyncTask task) {
        IssueSyncStatus status = syncStatusMapper.selectOne(new LambdaQueryWrapper<IssueSyncStatus>()
                .eq(IssueSyncStatus::getConfigId, configId)
                .eq(IssueSyncStatus::getSyncType, type.getCode())
                .eq(IssueSyncStatus::getIsDeleted, 0));
        if (status == null) {
            return;
        }
        status.setTotalCount(task.getTotalCount());
        status.setSuccessCount(task.getSuccessCount());
        status.setFailureCount(task.getFailureCount());
        status.setUnsyncedCount(Math.max(0,
                (task.getTotalCount() == null ? 0 : task.getTotalCount())
                        - (task.getProcessedCount() == null ? 0 : task.getProcessedCount())));
        status.setLastSyncTime(LocalDateTime.now());
        CloudEntitySupport.fillOnUpdate(status);
        syncStatusMapper.updateById(status);
    }
}
