package com.yaoai.pipeline.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yaoai.common.exception.BizException;
import com.yaoai.common.exception.ErrorCode;
import com.yaoai.domain.entity.ShotAsset;
import com.yaoai.domain.mapper.ShotAssetMapper;
import com.yaoai.pipeline.service.ShotAssetService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
@RequiredArgsConstructor
public class ShotAssetServiceImpl implements ShotAssetService {

    private static final String TYPE_VIDEO = "video";

    private final ShotAssetMapper shotAssetMapper;
    private final ObjectMapper objectMapper;

    @Override
    public List<ShotAsset> listByStoryboard(Long storyboardId, Long tenantId) {
        return shotAssetMapper.findByStoryboard(storyboardId, tenantId);
    }

    @Override
    @Transactional
    public ShotAsset activateAsset(Long assetId, Long storyboardId, Long tenantId) {
        ShotAsset asset = shotAssetMapper.selectById(assetId);
        if (asset == null
                || !tenantId.equals(asset.getTenantId())
                || !storyboardId.equals(asset.getStoryboardId())) {
            throw new BizException(ErrorCode.NOT_FOUND, "镜头素材不存在");
        }
        shotAssetMapper.deactivateActive(storyboardId, tenantId, asset.getAssetType());
        ShotAsset patch = new ShotAsset();
        patch.setId(assetId);
        patch.setIsActive(1);
        shotAssetMapper.updateById(patch);
        return shotAssetMapper.selectById(assetId);
    }

    @Override
    @Transactional
    public ShotAsset recordPendingVideoAsset(Long tenantId, Long projectId, Long episodeId, Long storyboardId,
                                             Long taskId, String prompt, String modelProvider, String modelId,
                                             List<String> characterImageKeys, String sceneImageKey,
                                             List<String> propImageKeys, String styleImageKey,
                                             Map<String, Object> meta) {
        if (storyboardId == null) {
            return null;
        }
        shotAssetMapper.deactivateActive(storyboardId, tenantId, TYPE_VIDEO);
        Integer maxVersion = shotAssetMapper.maxVersion(storyboardId, tenantId, TYPE_VIDEO);

        Map<String, Object> metaPayload = new LinkedHashMap<>();
        if (meta != null) {
            metaPayload.putAll(meta);
        }
        metaPayload.put("sceneImageKey", sceneImageKey);
        metaPayload.put("propImageKeys", propImageKeys);
        metaPayload.put("styleImageKey", styleImageKey);

        ShotAsset asset = new ShotAsset();
        asset.setTenantId(tenantId);
        asset.setProjectId(projectId);
        asset.setEpisodeId(episodeId);
        asset.setStoryboardId(storyboardId);
        asset.setAssetType(TYPE_VIDEO);
        asset.setSourceTaskId(taskId);
        asset.setPrompt(prompt);
        asset.setModelProvider(modelProvider);
        asset.setModelId(modelId);
        asset.setAssetVersion((maxVersion == null ? 0 : maxVersion) + 1);
        asset.setCharacters(toJson(characterImageKeys));
        asset.setMetaJson(toJson(metaPayload));
        asset.setStatus("generating");
        asset.setIsActive(1);
        shotAssetMapper.insert(asset);
        return asset;
    }

    @Override
    public void markVideoAssetSucceeded(Long tenantId, Long taskId, String videoUrl) {
        updateVideoAssetStatus(tenantId, taskId, "ready", videoUrl, null);
    }

    @Override
    public void markVideoAssetFailed(Long tenantId, Long taskId, String errorMessage) {
        updateVideoAssetStatus(tenantId, taskId, "failed", null, errorMessage);
    }

    @Override
    public void deactivateBySourceTask(Long tenantId, Long taskId) {
        if (taskId == null) {
            return;
        }
        shotAssetMapper.deactivateBySourceTask(taskId, tenantId);
    }

    private void updateVideoAssetStatus(Long tenantId, Long taskId, String status, String videoUrl, String errorMessage) {
        if (taskId == null) {
            return;
        }
        ShotAsset existing = shotAssetMapper.findBySourceTask(taskId, tenantId);
        if (existing == null) {
            log.debug("No shot asset found for task {}, skip asset status update", taskId);
            return;
        }
        ShotAsset patch = new ShotAsset();
        patch.setId(existing.getId());
        patch.setStatus(status);
        patch.setExternalUrl(videoUrl);
        patch.setErrorMessage(errorMessage);
        shotAssetMapper.updateById(patch);
    }

    private String toJson(Object value) {
        if (value == null) {
            return null;
        }
        if (value instanceof List<?> list && list.isEmpty()) {
            return null;
        }
        try {
            return objectMapper.writeValueAsString(value);
        } catch (JsonProcessingException e) {
            log.warn("Failed to serialize shot asset metadata: {}", e.getMessage());
            return null;
        }
    }
}
