package com.ruoyi.generator.service.front;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.generator.domain.front.AiGenerationTask;
import com.ruoyi.generator.domain.front.FrontProject;
import com.ruoyi.generator.domain.front.FrontProjectGeneration;
import com.ruoyi.generator.domain.front.dto.AiGenerationTaskCreateRequest;
import com.ruoyi.generator.domain.front.dto.AiGenerationTaskStatusResponse;
import com.ruoyi.generator.domain.front.dto.AiQuotaResponse;
import com.ruoyi.generator.mapper.front.AiGenerationTaskMapper;
import com.ruoyi.generator.mapper.front.FrontProjectGenerationMapper;
import com.ruoyi.generator.mapper.front.FrontProjectMapper;

@Service
public class AiGenerationTaskServiceImpl implements IAiGenerationTaskService
{
    private static final int MAX_ATTEMPTS = 3;

    @Autowired
    private FrontProjectMapper frontProjectMapper;
    @Autowired
    private AiGenerationTaskMapper aiGenerationTaskMapper;
    @Autowired(required = false)
    private FrontProjectGenerationMapper frontProjectGenerationMapper;
    @Autowired
    private AiQuotaService aiQuotaService;
    @Autowired(required = false)
    private AiGenerationTaskWorker aiGenerationTaskWorker;
    @Autowired(required = false)
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Override
    @Transactional
    public AiGenerationTaskStatusResponse createTask(Long userId, Long projectId, AiGenerationTaskCreateRequest request)
    {
        assertOwnedProject(userId, projectId);
        validateRequest(request);
        String requestPayload = JSON.toJSONString(request);
        String requestHash = sha256(request.getGenerateType() + ":" + requestPayload);
        AiGenerationTask existing = aiGenerationTaskMapper.selectActiveTaskByRequestHash(userId, projectId, requestHash);
        if (existing != null)
        {
            return toResponse(existing);
        }
        aiQuotaService.reserve(userId);
        AiGenerationTask task = new AiGenerationTask();
        task.setProjectId(projectId);
        task.setUserId(userId);
        task.setGenerateType(request.getGenerateType());
        task.setProvider("deepseek");
        task.setModel("deepseek-chat");
        task.setStatus("QUEUED");
        task.setRequestHash(requestHash);
        task.setRequestPayload(requestPayload);
        task.setAttempts(0);
        task.setMaxAttempts(MAX_ATTEMPTS);
        task.setProgress(0);
        task.setCurrentStep("等待生成");
        task.setNextRetryTime(new Date());
        aiGenerationTaskMapper.insertAiGenerationTask(task);
        dispatch(task.getTaskId());
        return toResponse(task);
    }

    @Override
    public AiGenerationTaskStatusResponse getTask(Long userId, Long projectId, Long taskId)
    {
        AiGenerationTask task = selectOwnedTask(userId, projectId, taskId);
        return toResponse(task);
    }

    @Override
    @Transactional
    public AiGenerationTaskStatusResponse retryTask(Long userId, Long projectId, Long taskId)
    {
        AiGenerationTask task = selectOwnedTask(userId, projectId, taskId);
        if (!"FAILED".equals(task.getStatus()) && !"RETRY_WAITING".equals(task.getStatus()))
        {
            throw new ServiceException("当前任务状态不允许重试");
        }
        aiQuotaService.reserve(userId);
        task.setStatus("QUEUED");
        task.setProgress(0);
        task.setCurrentStep("等待重试");
        task.setErrorCode("");
        task.setErrorMessage("");
        task.setNextRetryTime(new Date());
        aiGenerationTaskMapper.updateAiGenerationTask(task);
        dispatch(taskId);
        return toResponse(task);
    }

    @Override
    @Transactional
    public AiGenerationTaskStatusResponse cancelTask(Long userId, Long projectId, Long taskId)
    {
        AiGenerationTask task = selectOwnedTask(userId, projectId, taskId);
        if (!"QUEUED".equals(task.getStatus()) && !"RETRY_WAITING".equals(task.getStatus()))
        {
            throw new ServiceException("当前任务状态不允许取消");
        }
        task.setStatus("CANCELED");
        task.setProgress(0);
        task.setCurrentStep("已取消");
        task.setFinishedAt(new Date());
        aiGenerationTaskMapper.updateAiGenerationTask(task);
        aiQuotaService.releaseRunning(userId);
        return toResponse(task);
    }

    @Override
    public List<FrontProjectGeneration> listGenerations(Long userId, Long projectId)
    {
        assertOwnedProject(userId, projectId);
        return frontProjectGenerationMapper.selectGenerationsByProjectId(projectId);
    }

    @Override
    public AiQuotaResponse getQuota(Long userId)
    {
        return aiQuotaService.getQuota(userId);
    }

    private FrontProject assertOwnedProject(Long userId, Long projectId)
    {
        FrontProject project = frontProjectMapper.selectFrontProjectByUserAndId(userId, projectId);
        if (project == null)
        {
            throw new ServiceException("项目不存在或无权限");
        }
        return project;
    }

    private AiGenerationTask selectOwnedTask(Long userId, Long projectId, Long taskId)
    {
        AiGenerationTask task = aiGenerationTaskMapper.selectTaskForUser(userId, projectId, taskId);
        if (task == null)
        {
            throw new ServiceException("任务不存在或无权限");
        }
        return task;
    }

    private void validateRequest(AiGenerationTaskCreateRequest request)
    {
        if (request == null || StringUtils.isEmpty(request.getGenerateType()))
        {
            throw new ServiceException("生成类型不能为空");
        }
        if (!"app_blueprint".equals(request.getGenerateType()) && !"database".equals(request.getGenerateType())
                && !"business_blueprint".equals(request.getGenerateType()))
        {
            throw new ServiceException("不支持的生成类型");
        }
    }

    private AiGenerationTaskStatusResponse toResponse(AiGenerationTask task)
    {
        AiGenerationTaskStatusResponse response = new AiGenerationTaskStatusResponse();
        response.setTaskId(task.getTaskId());
        response.setProjectId(task.getProjectId());
        response.setGenerationId(task.getGenerationId());
        response.setGenerateType(task.getGenerateType());
        response.setStatus(task.getStatus());
        response.setProgress(task.getProgress());
        response.setCurrentStep(task.getCurrentStep());
        response.setResultPayload(task.getResultPayload());
        response.setErrorMessage(task.getErrorMessage());
        response.setAttempts(task.getAttempts());
        response.setMaxAttempts(task.getMaxAttempts());
        response.setNextRetryTime(task.getNextRetryTime());
        response.setCreateTime(task.getCreateTime());
        response.setUpdateTime(task.getUpdateTime());
        return response;
    }

    private String sha256(String value)
    {
        try
        {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] hash = digest.digest(value.getBytes(StandardCharsets.UTF_8));
            StringBuilder builder = new StringBuilder();
            for (byte b : hash)
            {
                builder.append(String.format("%02x", b));
            }
            return builder.toString();
        }
        catch (NoSuchAlgorithmException e)
        {
            throw new ServiceException("生成请求指纹失败").setDetailMessage(e.getMessage());
        }
    }

    private void dispatch(final Long taskId)
    {
        if (taskId == null || aiGenerationTaskWorker == null || threadPoolTaskExecutor == null)
        {
            return;
        }
        threadPoolTaskExecutor.execute(new Runnable()
        {
            @Override
            public void run()
            {
                aiGenerationTaskWorker.processTask(taskId);
            }
        });
    }
}
