package com.ruoyi.generator.service.front;

import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.generator.domain.front.AiGenerationTask;
import com.ruoyi.generator.domain.front.AiUsageLedger;
import com.ruoyi.generator.domain.front.dto.AiGenerationTaskCreateRequest;
import com.ruoyi.generator.domain.front.dto.GenerateAppBlueprintRequest;
import com.ruoyi.generator.domain.front.dto.GenerateBusinessBlueprintRequest;
import com.ruoyi.generator.domain.front.dto.GenerateDatabaseRequest;
import com.ruoyi.generator.mapper.front.AiGenerationTaskMapper;
import com.ruoyi.generator.mapper.front.AiUsageLedgerMapper;

@Service
public class AiGenerationTaskWorker
{
    @Autowired
    private AiGenerationTaskMapper aiGenerationTaskMapper;
    @Autowired(required = false)
    private AiUsageLedgerMapper aiUsageLedgerMapper;
    @Autowired
    private IAiGenerateService aiGenerateService;
    @Autowired
    private AiQuotaService aiQuotaService;
    @Autowired
    private AiTaskRetryPolicy retryPolicy;
    @Autowired
    private AiCostCalculator costCalculator;
    @Autowired(required = false)
    private ScheduledExecutorService scheduledExecutorService;

    @PostConstruct
    public void startPolling()
    {
        if (scheduledExecutorService == null)
        {
            return;
        }
        scheduledExecutorService.scheduleWithFixedDelay(new Runnable()
        {
            @Override
            public void run()
            {
                processDueTasks(5);
            }
        }, 10, 10, TimeUnit.SECONDS);
    }

    public void processTask(Long taskId)
    {
        AiGenerationTask task = aiGenerationTaskMapper.selectAiGenerationTaskById(taskId);
        if (task == null)
        {
            return;
        }
        if (aiGenerationTaskMapper.claimTask(taskId, workerId()) == 0)
        {
            return;
        }
        int attempts = safe(task.getAttempts()) + 1;
        task.setAttempts(attempts);
        task.setStatus("RUNNING");
        task.setProgress(10);
        task.setCurrentStep("正在调用 AI");
        task.setStartedAt(new Date());
        aiGenerationTaskMapper.updateAiGenerationTask(task);

        try
        {
            Object result = execute(task);
            task.setStatus("SUCCEEDED");
            task.setProgress(100);
            task.setCurrentStep("生成完成");
            task.setResultPayload(JSON.toJSONString(result));
            task.setErrorCode("");
            task.setErrorMessage("");
            task.setFinishedAt(new Date());
            task.setInputTokens(estimateTokens(task.getRequestPayload()));
            task.setOutputTokens(estimateTokens(task.getResultPayload()));
            task.setTotalTokens(safe(task.getInputTokens()) + safe(task.getOutputTokens()));
            int totalTokens = safe(task.getTotalTokens());
            int costCents = costCalculator.estimateCostCents(task.getProvider(), task.getModel(), task.getInputTokens(), task.getOutputTokens());
            task.setCostCents(costCents);
            aiGenerationTaskMapper.updateAiGenerationTask(task);
            insertLedger(task, "1");
            aiQuotaService.settleCost(task.getUserId(), totalTokens, costCents);
        }
        catch (RuntimeException e)
        {
            String message = sanitize(e.getMessage());
            task.setErrorMessage(message);
            task.setProgress(0);
            if (retryPolicy.canRetry(message, attempts, safeMax(task.getMaxAttempts())))
            {
                task.setStatus("RETRY_WAITING");
                task.setCurrentStep("等待重试");
                task.setNextRetryTime(retryPolicy.nextRetryTime(attempts, new Date()));
            }
            else
            {
                task.setStatus("FAILED");
                task.setCurrentStep("生成失败");
                task.setFinishedAt(new Date());
            }
            aiGenerationTaskMapper.updateAiGenerationTask(task);
            insertLedger(task, "0");
        }
        finally
        {
            aiQuotaService.releaseRunning(task.getUserId());
        }
    }

    public int processDueTasks(int limit)
    {
        List<AiGenerationTask> tasks = aiGenerationTaskMapper.selectClaimableTasks(limit);
        if (tasks == null || tasks.isEmpty())
        {
            return 0;
        }
        int count = 0;
        for (AiGenerationTask task : tasks)
        {
            processTask(task.getTaskId());
            count++;
        }
        return count;
    }

    private Object execute(AiGenerationTask task)
    {
        AiGenerationTaskCreateRequest request = JSON.parseObject(task.getRequestPayload(), AiGenerationTaskCreateRequest.class);
        if ("app_blueprint".equals(task.getGenerateType()))
        {
            return aiGenerateService.generateAppBlueprint(task.getUserId(), task.getProjectId(), toAppBlueprintRequest(request));
        }
        if ("database".equals(task.getGenerateType()))
        {
            return aiGenerateService.generateDatabase(task.getUserId(), task.getProjectId(), toDatabaseRequest(request));
        }
        if ("business_blueprint".equals(task.getGenerateType()))
        {
            return aiGenerateService.generateBusinessBlueprint(task.getUserId(), task.getProjectId(), toBusinessBlueprintRequest(request));
        }
        throw new IllegalArgumentException("不支持的生成类型");
    }

    private GenerateAppBlueprintRequest toAppBlueprintRequest(AiGenerationTaskCreateRequest source)
    {
        GenerateAppBlueprintRequest request = new GenerateAppBlueprintRequest();
        request.setProjectName(source.getProjectName());
        request.setProjectDesc(source.getProjectDesc());
        request.setIndustryTemplate(source.getIndustryTemplate());
        request.setExtraRequirements(source.getExtraRequirements());
        return request;
    }

    private GenerateDatabaseRequest toDatabaseRequest(AiGenerationTaskCreateRequest source)
    {
        GenerateDatabaseRequest request = new GenerateDatabaseRequest();
        request.setProjectName(source.getProjectName());
        request.setProjectDesc(source.getProjectDesc());
        request.setIndustryTemplate(source.getIndustryTemplate());
        request.setExtraRequirements(source.getExtraRequirements());
        request.setAppBlueprint(source.getAppBlueprint());
        return request;
    }

    private GenerateBusinessBlueprintRequest toBusinessBlueprintRequest(AiGenerationTaskCreateRequest source)
    {
        GenerateBusinessBlueprintRequest request = new GenerateBusinessBlueprintRequest();
        request.setProjectName(source.getProjectName());
        request.setProjectDesc(source.getProjectDesc());
        request.setIndustryTemplate(source.getIndustryTemplate());
        request.setExtraRequirements(source.getExtraRequirements());
        return request;
    }

    private void insertLedger(AiGenerationTask task, String success)
    {
        if (aiUsageLedgerMapper == null)
        {
            return;
        }
        AiUsageLedger ledger = new AiUsageLedger();
        ledger.setTaskId(task.getTaskId());
        ledger.setGenerationId(task.getGenerationId());
        ledger.setProjectId(task.getProjectId());
        ledger.setUserId(task.getUserId());
        ledger.setGenerateType(task.getGenerateType());
        ledger.setProvider(task.getProvider());
        ledger.setModel(task.getModel());
        ledger.setInputTokens(task.getInputTokens());
        ledger.setOutputTokens(task.getOutputTokens());
        ledger.setTotalTokens(task.getTotalTokens());
        ledger.setCostCents(task.getCostCents());
        ledger.setSuccess(success);
        ledger.setErrorMessage(task.getErrorMessage());
        aiUsageLedgerMapper.insertAiUsageLedger(ledger);
    }

    private String workerId()
    {
        return "ai-task-worker-" + UUID.randomUUID().toString();
    }

    private int safe(Integer value)
    {
        return value == null ? 0 : value;
    }

    private int estimateTokens(String text)
    {
        if (StringUtils.isEmpty(text))
        {
            return 0;
        }
        return Math.max(1, (text.length() + 3) / 4);
    }

    private int safeMax(Integer value)
    {
        return value == null || value <= 0 ? 3 : value;
    }

    private String sanitize(String message)
    {
        if (StringUtils.isEmpty(message))
        {
            return "";
        }
        String sanitized = message.replaceAll("[\\p{Cntrl}]", " ");
        return sanitized.length() > 1000 ? sanitized.substring(0, 1000) : sanitized;
    }
}
