package com.tasteby.service;

import com.tasteby.domain.VideoDetail;
import com.tasteby.domain.VideoRestaurantLink;
import com.tasteby.domain.VideoSummary;
import com.tasteby.mapper.VideoMapper;
import com.tasteby.util.IdGenerator;
import com.tasteby.util.JsonUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
public class VideoService {

    private final VideoMapper mapper;

    public VideoService(VideoMapper mapper) {
        this.mapper = mapper;
    }

    public List<VideoSummary> findAll(String status) {
        return mapper.findAll(status);
    }

    public VideoDetail findDetail(String id) {
        VideoDetail detail = mapper.findDetail(id);
        if (detail == null) return null;
        List<VideoRestaurantLink> restaurants = mapper.findVideoRestaurants(id);
        if (restaurants != null) {
            restaurants.forEach(r -> r.setEvaluation(JsonUtil.normalizeEvaluation(r.getEvaluation())));
        }
        detail.setRestaurants(restaurants != null ? restaurants : List.of());
        return detail;
    }

    public void updateTitle(String id, String title) {
        mapper.updateTitle(id, title);
    }

    public void updateStatus(String id, String status) {
        mapper.updateStatus(id, status);
    }

    @Transactional
    public void delete(String id) {
        mapper.deleteVectorsByVideoOnly(id);
        mapper.deleteReviewsByVideoOnly(id);
        mapper.deleteFavoritesByVideoOnly(id);
        mapper.deleteRestaurantsByVideoOnly(id);
        mapper.deleteVideoRestaurants(id);
        mapper.deleteVideo(id);
    }

    @Transactional
    public void deleteVideoRestaurant(String videoId, String restaurantId) {
        mapper.deleteOneVideoRestaurant(videoId, restaurantId);
        mapper.cleanupOrphanVectors(restaurantId);
        mapper.cleanupOrphanReviews(restaurantId);
        mapper.cleanupOrphanFavorites(restaurantId);
        mapper.cleanupOrphanRestaurant(restaurantId);
    }

    @Transactional
    public int saveVideosBatch(String channelId, List<Map<String, Object>> videos) {
        Set<String> existing = new HashSet<>(mapper.getExistingVideoIds(channelId));
        int saved = 0;
        for (var v : videos) {
            String videoId = (String) v.get("video_id");
            if (existing.contains(videoId)) continue;
            String id = IdGenerator.newId();
            mapper.insertVideo(id, channelId, videoId,
                    (String) v.get("title"), (String) v.get("url"), (String) v.get("published_at"));
            saved++;
        }
        return saved;
    }

    public Set<String> getExistingVideoIds(String channelId) {
        return new HashSet<>(mapper.getExistingVideoIds(channelId));
    }

    public String getLatestVideoDate(String channelId) {
        return mapper.getLatestVideoDate(channelId);
    }

    public List<Map<String, Object>> findPendingVideos(int limit) {
        return mapper.findPendingVideos(limit).stream()
                .map(JsonUtil::lowerKeys).toList();
    }

    public List<Map<String, Object>> findVideosForBulkExtract() {
        var rows = mapper.findVideosForBulkExtract();
        return rows.stream().map(row -> {
            var r = JsonUtil.lowerKeys(row);
            // Parse CLOB transcript
            Object transcript = r.get("transcript_text");
            r.put("transcript", JsonUtil.readClob(transcript));
            r.remove("transcript_text");
            return r;
        }).toList();
    }

    public void updateTranscript(String id, String transcript) {
        mapper.updateTranscript(id, transcript);
    }

    public void updateVideoFields(String id, String status, String transcript, String llmResponse) {
        mapper.updateVideoFields(id, status, transcript, llmResponse);
    }

    public List<Map<String, Object>> findVideosWithoutTranscript() {
        var rows = mapper.findVideosWithoutTranscript();
        return rows.stream().map(JsonUtil::lowerKeys).toList();
    }

    public List<Map<String, Object>> findVideosByIds(List<String> ids) {
        var rows = mapper.findVideosByIds(ids);
        return rows.stream().map(JsonUtil::lowerKeys).toList();
    }

    public List<Map<String, Object>> findVideosForExtractByIds(List<String> ids) {
        var rows = mapper.findVideosForExtractByIds(ids);
        return rows.stream().map(row -> {
            var r = JsonUtil.lowerKeys(row);
            Object transcript = r.get("transcript_text");
            r.put("transcript", JsonUtil.readClob(transcript));
            r.remove("transcript_text");
            return r;
        }).toList();
    }

    public void updateVideoRestaurantFields(String videoId, String restaurantId,
                                             String foodsJson, String evaluation, String guestsJson) {
        mapper.updateVideoRestaurantFields(videoId, restaurantId, foodsJson, evaluation, guestsJson);
    }
}
