package com.yaoai.pipeline.async;

import com.yaoai.ai.providers.service.SeedanceService;
import com.yaoai.billing.dto.BillingChargeRequest;
import com.yaoai.billing.service.BillingService;
import com.yaoai.domain.entity.AiTask;
import com.yaoai.domain.mapper.AiTaskMapper;
import com.yaoai.pipeline.service.ImageGenPipelineService;
import com.yaoai.pipeline.service.ShotAssetService;
import com.yaoai.storage.service.TosService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Slf4j
@Component
@RequiredArgsConstructor
public class VideoTaskAsyncProcessor {

    private final AiTaskMapper aiTaskMapper;
    private final ImageGenPipelineService imageGenPipelineService;
    private final SeedanceService seedanceService;
    private final TosService tosService;
    private final BillingService billingService;
    private final ShotAssetService shotAssetService;

    /**
     * 异步执行视频生成流程：
     * - preImageKeys 为空 → 调用 Seedream 文生图，再提交 Seedance
     * - preImageKeys 非空 → 直接用这些 TOS key 作为 @图1、@图2... 参考图提交 Seedance
     *
     * 提交 Ark 后立即结束，不阻塞 @Async 线程；任务完成由 {@link VideoTaskPoller} 定时扫描处理。
     *
     * @param preImageKeys 按 @图1/@图2... 顺序排列的 TOS key 列表，空列表则走文生图
     * @param durationSeconds 视频时长（秒），<=0 则使用默认值 5
     * @param ratio 视频宽高比，如 "16:9" / "9:16" / "1:1"，空/非法值由下游兜底
     * @param generateAudio 是否生成配音
     */
    @Async
    public void processTextToVideo(Long taskId, Long tenantId, Long userId, Long projectId,
                                   String imagePrompt, String videoPrompt,
                                   List<String> preImageKeys, int durationSeconds,
                                   String ratio, boolean generateAudio, String model) {
        log.info("Async text-to-video started: taskId={}, preImages={}, duration={}s, ratio={}, audio={}, model={}",
                taskId, preImageKeys.size(), durationSeconds, ratio, generateAudio, model);
        try {
            BillingChargeRequest videoCharge = BillingChargeRequest.builder()
                    .tenantId(tenantId)
                    .userId(userId)
                    .projectId(projectId)
                    .operation("video_generate")
                    .modality("VIDEO")
                    .modelProvider(seedanceService.getProvider())
                    .modelId(seedanceService.getModelId())
                    .modelName(seedanceService.getModelName())
                    .unitCount(1)
                    .refId(String.valueOf(taskId))
                    .build();
            BigDecimal estimatedCost = billingService.estimateCost(videoCharge);
            if (preImageKeys.isEmpty()) {
                estimatedCost = estimatedCost.add(billingService.estimateCost(BillingChargeRequest.builder()
                        .tenantId(tenantId)
                        .userId(userId)
                        .projectId(projectId)
                        .operation("image_generate")
                        .modality("IMAGE")
                        .unitCount(1)
                        .meta(Map.of("size", "2048x2048"))
                        .build()));
            }
            billingService.checkBalance(tenantId, estimatedCost);

            List<String> presignedUrls = new ArrayList<>();
            String primaryImageKey;

            if (!preImageKeys.isEmpty()) {
                // 有预设参考图：按顺序转为预签名 URL（对应 @图1、@图2...）
                for (String key : preImageKeys) {
                    presignedUrls.add(tosService.presignedGetUrl(key, 3600));
                }
                primaryImageKey = preImageKeys.get(0);
                log.info("Using {} pre-existing reference image(s): taskId={}", preImageKeys.size(), taskId);
            } else {
                // 无预设参考图：调用 Seedream 文生图
                primaryImageKey = imageGenPipelineService.generateAndStore(tenantId, userId, projectId, imagePrompt);
                presignedUrls.add(tosService.presignedGetUrl(primaryImageKey, 3600));
                log.info("Image generated and stored: taskId={}, key={}", taskId, primaryImageKey);
            }

            // 提交 Seedance，传入所有参考图 + 时长
            int duration = durationSeconds > 0 ? Math.min(15, Math.max(5, durationSeconds)) : 5;
            String externalTaskId = seedanceService.submitVideoTask(presignedUrls, videoPrompt, duration, generateAudio, ratio, model);
            log.info("Seedance task submitted: taskId={}, externalId={}, images={}, duration={}s",
                    taskId, externalTaskId, presignedUrls.size(), duration);

            // 更新任务为 submitted；后续状态查询交给 VideoTaskPoller
            AiTask update = new AiTask();
            update.setId(taskId);
            update.setStatus("submitted");
            update.setInputImageKey(primaryImageKey);
            update.setExternalTaskId(externalTaskId);
            aiTaskMapper.updateById(update);

            billingService.charge(videoCharge);
            log.info("Async text-to-video submitted: taskId={}, externalId={}", taskId, externalTaskId);

        } catch (Exception e) {
            log.error("Async text-to-video failed: taskId={}", taskId, e);
            AiTask failure = new AiTask();
            failure.setId(taskId);
            failure.setStatus("failed");
            failure.setErrorMessage(e.getMessage() != null ? e.getMessage() : "生成失败");
            aiTaskMapper.updateById(failure);
            shotAssetService.markVideoAssetFailed(tenantId, taskId, failure.getErrorMessage());
        }
    }
}
