package com.storycove.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
public class AsyncImageProcessingService {

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

    private final ImageService imageService;
    private final StoryService storyService;
    private final ImageProcessingProgressService progressService;

    @org.springframework.beans.factory.annotation.Value("${storycove.app.public-url:http://localhost:6925}")
    private String publicUrl;

    @Autowired
    public AsyncImageProcessingService(ImageService imageService,
                                     StoryService storyService,
                                     ImageProcessingProgressService progressService) {
        this.imageService = imageService;
        this.storyService = storyService;
        this.progressService = progressService;
    }

    @Async
    public CompletableFuture<Void> processStoryImagesAsync(UUID storyId, String contentHtml) {
        logger.info("Starting async image processing for story: {}", storyId);

        try {
            // Count external images first
            int externalImageCount = countExternalImages(contentHtml);

            if (externalImageCount == 0) {
                logger.debug("No external images found for story {}", storyId);
                return CompletableFuture.completedFuture(null);
            }

            // Start progress tracking
            ImageProcessingProgressService.ImageProcessingProgress progress =
                progressService.startProgress(storyId, externalImageCount);

            // Process images with progress updates
            ImageService.ContentImageProcessingResult result =
                processImagesWithProgress(contentHtml, storyId, progress);

            // Update story with processed content if changed
            if (!result.getProcessedContent().equals(contentHtml)) {
                progressService.updateProgress(storyId, progress.getTotalImages(),
                    "Saving processed content", "Updating story content");

                storyService.updateContentOnly(storyId, result.getProcessedContent());

                progressService.completeProgress(storyId,
                    String.format("Completed: %d images processed", result.getDownloadedImages().size()));

                logger.info("Async image processing completed for story {}: {} images processed",
                           storyId, result.getDownloadedImages().size());
            } else {
                progressService.completeProgress(storyId, "Completed: No images needed processing");
            }

            // Clean up progress after a delay to allow frontend to see completion
            CompletableFuture.runAsync(() -> {
                try {
                    Thread.sleep(5000); // 5 seconds delay
                    progressService.removeProgress(storyId);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });

        } catch (Exception e) {
            logger.error("Async image processing failed for story {}: {}", storyId, e.getMessage(), e);
            progressService.setError(storyId, e.getMessage());
        }

        return CompletableFuture.completedFuture(null);
    }

    private int countExternalImages(String contentHtml) {
        if (contentHtml == null || contentHtml.trim().isEmpty()) {
            return 0;
        }

        Pattern imgPattern = Pattern.compile("<img[^>]+src=[\"']([^\"']+)[\"'][^>]*>", Pattern.CASE_INSENSITIVE);
        Matcher matcher = imgPattern.matcher(contentHtml);

        int count = 0;
        while (matcher.find()) {
            String src = matcher.group(1);
            if (isExternalUrl(src)) {
                count++;
            }
        }

        return count;
    }

    /**
     * Check if a URL is external (not from this application).
     * Returns true if the URL should be downloaded, false if it's already local.
     */
    private boolean isExternalUrl(String url) {
        if (url == null || url.trim().isEmpty()) {
            return false;
        }

        // Skip data URLs
        if (url.startsWith("data:")) {
            return false;
        }

        // Skip relative URLs (local paths)
        if (url.startsWith("/")) {
            return false;
        }

        // Skip URLs that are already pointing to our API
        if (url.contains("/api/files/images/")) {
            return false;
        }

        // Check if URL starts with the public URL (our own domain)
        if (publicUrl != null && !publicUrl.trim().isEmpty()) {
            String normalizedUrl = url.trim().toLowerCase();
            String normalizedPublicUrl = publicUrl.trim().toLowerCase();

            // Remove trailing slash from public URL for comparison
            if (normalizedPublicUrl.endsWith("/")) {
                normalizedPublicUrl = normalizedPublicUrl.substring(0, normalizedPublicUrl.length() - 1);
            }

            if (normalizedUrl.startsWith(normalizedPublicUrl)) {
                logger.debug("URL is from this application (matches publicUrl): {}", url);
                return false;
            }
        }

        // If it's an HTTP(S) URL that didn't match our filters, it's external
        if (url.startsWith("http://") || url.startsWith("https://")) {
            logger.debug("URL is external: {}", url);
            return true;
        }

        // For any other format, consider it non-external (safer default)
        return false;
    }

    private ImageService.ContentImageProcessingResult processImagesWithProgress(
            String contentHtml, UUID storyId, ImageProcessingProgressService.ImageProcessingProgress progress) {

        // Use a custom version of processContentImages that provides progress callbacks
        return imageService.processContentImagesWithProgress(contentHtml, storyId,
            (currentUrl, processedCount, totalCount) -> {
                progressService.updateProgress(storyId, processedCount, currentUrl,
                    String.format("Processing image %d of %d", processedCount + 1, totalCount));
            });
    }
}