package com.yaoai.pipeline.async;

import com.yaoai.ai.providers.model.VideoTaskResult;
import com.yaoai.ai.providers.service.SeedanceService;
import com.yaoai.domain.entity.AiTask;
import com.yaoai.domain.mapper.AiTaskMapper;
import com.yaoai.pipeline.service.ShotAssetService;
import com.yaoai.storage.service.TosService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

/**
 * 单条视频任务的查询与完成处理：查 Ark → 更新 DB → 转存视频到自家 TOS。
 * 给 {@link VideoTaskPoller} 调用，未来若加管理后台补救接口也可复用。
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class VideoTaskCompletionService {

    private final AiTaskMapper aiTaskMapper;
    private final SeedanceService seedanceService;
    private final TosService tosService;
    private final ShotAssetService shotAssetService;
    private final HttpClient httpClient = HttpClient.newBuilder()
            .connectTimeout(Duration.ofSeconds(10))
            .build();

    /**
     * 单次轮询一个任务：查 Ark 状态并按状态更新 DB；succeeded 时把视频转存到我们桶。
     * 返回此任务在本轮处理后是否进入终态（succeeded/failed）。
     */
    public boolean pollOnce(AiTask task) {
        Long taskId = task.getId();
        String externalTaskId = task.getExternalTaskId();
        try {
            VideoTaskResult result = seedanceService.getTaskStatus(externalTaskId);
            String status = result.getStatus();
            log.debug("Polling Ark: taskId={}, externalId={}, status={}", taskId, externalTaskId, status);

            if ("succeeded".equals(status) || "failed".equals(status)) {
                AiTask done = new AiTask();
                done.setId(taskId);
                done.setStatus(status);
                if (result.getVideoUrl() != null) {
                    String persistentUrl = persistVideoToTos(
                            task.getTenantId(), task.getProjectId(), taskId, result.getVideoUrl());
                    done.setResultVideoUrl(persistentUrl);
                }
                if (result.getErrorMessage() != null) {
                    done.setErrorMessage(result.getErrorMessage());
                }
                aiTaskMapper.updateById(done);
                if ("succeeded".equals(status)) {
                    shotAssetService.markVideoAssetSucceeded(
                            task.getTenantId(), taskId, done.getResultVideoUrl());
                } else {
                    shotAssetService.markVideoAssetFailed(
                            task.getTenantId(), taskId, done.getErrorMessage());
                }
                log.info("Video task completed: taskId={}, status={}, url={}",
                        taskId, status, done.getResultVideoUrl());
                return true;
            }

            // running 时同步状态，便于前端区分 submitted/running
            if ("running".equals(status) && !"running".equals(task.getStatus())) {
                AiTask running = new AiTask();
                running.setId(taskId);
                running.setStatus("running");
                aiTaskMapper.updateById(running);
            }
            return false;
        } catch (Exception e) {
            log.warn("Ark poll error (will retry): taskId={}, error={}", taskId, e.getMessage());
            return false;
        }
    }

    /**
     * 把 Ark 临时视频 URL 下载下来上传到我们 public-read TOS bucket，返回永不过期的公开 URL。
     * 失败时退回原始 URL（24h 内仍可用）+ 错误日志，不阻塞任务完成流程。
     */
    public String persistVideoToTos(Long tenantId, Long projectId, Long taskId, String arkVideoUrl) {
        try {
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create(arkVideoUrl))
                    .timeout(Duration.ofMinutes(2))
                    .GET()
                    .build();
            HttpResponse<byte[]> response = httpClient.send(request, HttpResponse.BodyHandlers.ofByteArray());
            if (response.statusCode() != 200) {
                log.warn("Download Ark video failed (status={}), keep raw URL: taskId={}", response.statusCode(), taskId);
                return arkVideoUrl;
            }
            byte[] bytes = response.body();
            String key = String.format("%d/%d/video/%d.mp4", tenantId, projectId, taskId);
            try (var is = new ByteArrayInputStream(bytes)) {
                tosService.upload(key, is, bytes.length, "video/mp4");
            }
            String publicUrl = tosService.publicUrl(key);
            log.info("Video persisted to TOS: taskId={}, key={}, size={}", taskId, key, bytes.length);
            return publicUrl;
        } catch (Exception e) {
            log.error("Persist Ark video to TOS failed, fallback to raw URL: taskId={}", taskId, e);
            return arkVideoUrl;
        }
    }
}
