package com.storycove.service;

import com.storycove.config.AudioCoveProperties;
import com.storycove.dto.AudioCoveIngestRequest;
import com.storycove.entity.Collection;
import com.storycove.entity.CollectionStory;
import com.storycove.entity.Story;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestClient;
import org.springframework.web.client.RestClientException;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Comparator;
import java.util.List;
import java.util.UUID;

@Service
public class AudioCoveService {

    private static final Logger logger = LoggerFactory.getLogger(AudioCoveService.class);

    private final StoryService storyService;
    private final CollectionService collectionService;
    private final AudioCoveProperties audioCoveProperties;
    private final String publicUrl;
    private final RestClient restClient;

    public AudioCoveService(StoryService storyService,
                            CollectionService collectionService,
                            AudioCoveProperties audioCoveProperties,
                            @Value("${storycove.app.public-url}") String publicUrl) {
        this.storyService = storyService;
        this.collectionService = collectionService;
        this.audioCoveProperties = audioCoveProperties;
        this.publicUrl = publicUrl;
        this.restClient = RestClient.create();
    }

    @Transactional(readOnly = true)
    public String ingestStory(UUID storyId) {
        if (!audioCoveProperties.isConfigured()) {
            throw new IllegalStateException("AudioCove URL is not configured. Set the AUDIOCOVE_URL environment variable.");
        }

        Story story = storyService.findById(storyId);
        AudioCoveIngestRequest request = buildIngestRequest(story);

        logger.info("Sending story '{}' ({}) to AudioCove", story.getTitle(), storyId);

        try {
            String response = restClient.post()
                    .uri(audioCoveProperties.getUrl() + "/api/ingest")
                    .header("X-API-Key", audioCoveProperties.getApiKey())
                    .contentType(MediaType.APPLICATION_JSON)
                    .body(request)
                    .retrieve()
                    .body(String.class);

            logger.info("AudioCove ingest successful for story '{}'", story.getTitle());
            return response;
        } catch (RestClientException e) {
            logger.error("AudioCove ingest failed for story '{}': {}", story.getTitle(), e.getMessage());
            throw e;
        }
    }

    @Transactional(readOnly = true)
    public String ingestCollection(UUID collectionId) {
        if (!audioCoveProperties.isConfigured()) {
            throw new IllegalStateException("AudioCove URL is not configured. Set the AUDIOCOVE_URL environment variable.");
        }

        Collection collection = collectionService.findById(collectionId);
        List<CollectionStory> collectionStories = collection.getCollectionStories().stream()
                .sorted(Comparator.comparingInt(CollectionStory::getPosition))
                .toList();

        if (collectionStories.isEmpty()) {
            throw new IllegalStateException("Collection has no stories to send to AudioCove.");
        }

        StringBuilder combinedContent = new StringBuilder();
        for (int i = 0; i < collectionStories.size(); i++) {
            Story story = collectionStories.get(i).getStory();
            String chapterTitle = story.getTitle() + " - Part " + (i + 1) + " of Collection " + collection.getName();
            combinedContent.append("<h1>").append(chapterTitle).append("</h1>\n");
            if (story.getContentHtml() != null) {
                combinedContent.append(story.getContentHtml());
            }
            combinedContent.append("\n");
        }

        List<String> authors = collectionStories.stream()
                .map(cs -> cs.getStory().getAuthor())
                .filter(a -> a != null)
                .map(a -> a.getName())
                .distinct()
                .toList();
        String authorValue = String.join(", ", authors);

        AudioCoveIngestRequest request = new AudioCoveIngestRequest();
        request.setStoryId(collectionId.toString());
        request.setTitle(collection.getName());
        request.setAuthor(authorValue.isBlank() ? null : authorValue);
        request.setContentHtml(combinedContent.toString());
        request.setContentHash(computeContentHash(combinedContent.toString()));
        request.setCollection(collection.getName());

        List<String> allTags = collectionStories.stream()
                .flatMap(cs -> cs.getStory().getTags().stream())
                .map(tag -> tag.getName())
                .distinct()
                .toList();
        request.setTags(allTags);

        if (collection.getCoverImagePath() != null && !collection.getCoverImagePath().isBlank()) {
            request.setCoverImage(publicUrl + "/api/files/images/" + collection.getCoverImagePath());
        }

        logger.info("Sending collection '{}' ({}) to AudioCove with {} stories",
                collection.getName(), collectionId, collectionStories.size());

        try {
            String response = restClient.post()
                    .uri(audioCoveProperties.getUrl() + "/api/ingest")
                    .header("X-API-Key", audioCoveProperties.getApiKey())
                    .contentType(MediaType.APPLICATION_JSON)
                    .body(request)
                    .retrieve()
                    .body(String.class);

            logger.info("AudioCove ingest successful for collection '{}'", collection.getName());
            return response;
        } catch (RestClientException e) {
            logger.error("AudioCove ingest failed for collection '{}': {}", collection.getName(), e.getMessage());
            throw e;
        }
    }

    private AudioCoveIngestRequest buildIngestRequest(Story story) {
        AudioCoveIngestRequest request = new AudioCoveIngestRequest();

        request.setStoryId(story.getId().toString());
        request.setTitle(story.getTitle());
        request.setContentHtml(story.getContentHtml());
        request.setContentHash(computeContentHash(story.getContentHtml()));

        if (story.getAuthor() != null) {
            request.setAuthor(story.getAuthor().getName());
        }

        if (story.getSeries() != null) {
            request.setSeries(story.getSeries().getName());
            if (story.getVolume() != null) {
                request.setSeriesPart(story.getVolume().toString());
            }
        }

        List<String> tagNames = story.getTags().stream()
                .map(tag -> tag.getName())
                .toList();
        request.setTags(tagNames);

        if (story.getCoverPath() != null && !story.getCoverPath().isBlank()) {
            request.setCoverImage(publicUrl + "/api/files/images/" + story.getCoverPath());
        }

        return request;
    }

    private String computeContentHash(String content) {
        if (content == null) {
            content = "";
        }
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] hashBytes = digest.digest(content.getBytes(StandardCharsets.UTF_8));
            StringBuilder hex = new StringBuilder();
            for (byte b : hashBytes) {
                hex.append(String.format("%02x", b));
            }
            return "sha256:" + hex;
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalStateException("SHA-256 algorithm not available", e);
        }
    }
}
