package com.yaoai.pipeline.service.impl;

import com.yaoai.common.exception.BizException;
import com.yaoai.common.exception.ErrorCode;
import com.yaoai.domain.entity.Scene;
import com.yaoai.domain.mapper.SceneMapper;
import com.yaoai.storage.service.TosService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
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;
import java.util.Base64;

@Slf4j
@Service
@RequiredArgsConstructor
public class SceneImageTransferService {

    private final SceneMapper sceneMapper;
    private final TosService tosService;
    private final HttpClient httpClient = HttpClient.newBuilder()
            .connectTimeout(Duration.ofSeconds(10))
            .build();

    @Async
    public void transferSceneImageToTos(Long sceneId, Long tenantId, String temporaryImageUrl) {
        try {
            Scene scene = sceneMapper.selectById(sceneId);
            if (scene == null || !tenantId.equals(scene.getTenantId())) {
                log.warn("Skip scene image transfer: scene not found or tenant mismatch, sceneId={}", sceneId);
                return;
            }
            if (!temporaryImageUrl.equals(scene.getImageUrl())) {
                log.info("Skip stale scene image transfer: sceneId={}", sceneId);
                return;
            }

            log.info("Scene image transfer started: sceneId={}, temporaryUrl={}", sceneId, temporaryImageUrl);
            DownloadedImage image = downloadImage(temporaryImageUrl);
            String key = TosService.buildKey(
                    scene.getTenantId(),
                    scene.getProjectId(),
                    "scenes",
                    scene.getName() + "." + image.extension()
            );
            tosService.upload(key, new ByteArrayInputStream(image.bytes()), image.bytes().length, image.contentType());

            Scene latest = sceneMapper.selectById(sceneId);
            if (latest == null || !tenantId.equals(latest.getTenantId()) || !temporaryImageUrl.equals(latest.getImageUrl())) {
                log.info("Skip stale scene image replace after upload: sceneId={}", sceneId);
                return;
            }
            latest.setImageUrl(tosService.publicUrl(key));
            latest.setImageTosKey(key);
            latest.setStatus("ready");
            sceneMapper.updateById(latest);
            log.info("Scene image transfer completed: sceneId={}, key={}", sceneId, key);
        } catch (Exception e) {
            log.warn("Scene image transfer failed: sceneId={}, temporaryUrl={}", sceneId, temporaryImageUrl, e);
            markFailedIfStillCurrent(sceneId, tenantId, temporaryImageUrl);
        }
    }

    private void markFailedIfStillCurrent(Long sceneId, Long tenantId, String temporaryImageUrl) {
        Scene scene = sceneMapper.selectById(sceneId);
        if (scene == null || !tenantId.equals(scene.getTenantId()) || !temporaryImageUrl.equals(scene.getImageUrl())) {
            return;
        }
        scene.setStatus("failed");
        sceneMapper.updateById(scene);
    }

    private DownloadedImage downloadImage(String url) throws Exception {
        if (url != null && url.startsWith("data:")) {
            int comma = url.indexOf(',');
            int semicolon = url.indexOf(';');
            if (comma <= 0) {
                throw new BizException(ErrorCode.INTERNAL_ERROR, "图片 data URL 格式无效");
            }
            String contentType = semicolon > 5 ? url.substring(5, semicolon) : "image/png";
            return new DownloadedImage(Base64.getDecoder().decode(url.substring(comma + 1)), contentType, extensionFor(contentType));
        }

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .timeout(Duration.ofMinutes(2))
                .GET()
                .build();
        HttpResponse<byte[]> response = httpClient.send(request, HttpResponse.BodyHandlers.ofByteArray());
        if (response.statusCode() != 200) {
            throw new BizException(ErrorCode.INTERNAL_ERROR, "下载图片失败 HTTP " + response.statusCode());
        }
        String contentType = response.headers().firstValue("content-type")
                .map(value -> value.split(";")[0].trim())
                .filter(value -> value.startsWith("image/"))
                .orElseGet(() -> contentTypeFromUrl(url));
        return new DownloadedImage(response.body(), contentType, extensionFor(contentType));
    }

    private String contentTypeFromUrl(String url) {
        String lower = url == null ? "" : url.toLowerCase();
        if (lower.contains(".jpg") || lower.contains(".jpeg")) return "image/jpeg";
        if (lower.contains(".webp")) return "image/webp";
        if (lower.contains(".gif")) return "image/gif";
        return "image/png";
    }

    private String extensionFor(String contentType) {
        if ("image/jpeg".equalsIgnoreCase(contentType)) return "jpg";
        if ("image/webp".equalsIgnoreCase(contentType)) return "webp";
        if ("image/gif".equalsIgnoreCase(contentType)) return "gif";
        return "png";
    }

    private record DownloadedImage(byte[] bytes, String contentType, String extension) {
    }
}
