package com.storycove.controller;

import com.storycove.dto.HtmlSanitizationConfigDto;
import com.storycove.service.HtmlSanitizationService;
import com.storycove.service.ImageService;
import com.storycove.service.StoryService;
import com.storycove.entity.Story;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.List;
import java.util.HashMap;
import java.util.Optional;
import java.util.UUID;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.Files;
import java.io.IOException;

@RestController
@RequestMapping("/api/config")
public class ConfigController {

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

    private final HtmlSanitizationService htmlSanitizationService;
    private final ImageService imageService;
    private final StoryService storyService;

    @Value("${app.reading.speed.default:200}")
    private int defaultReadingSpeed;

    @Autowired
    public ConfigController(HtmlSanitizationService htmlSanitizationService, ImageService imageService, StoryService storyService) {
        this.htmlSanitizationService = htmlSanitizationService;
        this.imageService = imageService;
        this.storyService = storyService;
    }

    /**
     * Get the HTML sanitization configuration for frontend use
     * This allows the frontend to use the same sanitization rules as the backend
     */
    @GetMapping("/html-sanitization")
    public ResponseEntity<HtmlSanitizationConfigDto> getHtmlSanitizationConfig() {
        HtmlSanitizationConfigDto config = htmlSanitizationService.getConfiguration();
        return ResponseEntity.ok(config);
    }
    
    /**
     * Get application settings configuration
     */
    @GetMapping("/settings")
    public ResponseEntity<Map<String, Object>> getSettings() {
        Map<String, Object> settings = Map.of(
            "defaultReadingSpeed", defaultReadingSpeed
        );
        return ResponseEntity.ok(settings);
    }
    
    /**
     * Get reading speed for calculation purposes
     */
    @GetMapping("/reading-speed")
    public ResponseEntity<Map<String, Integer>> getReadingSpeed() {
        return ResponseEntity.ok(Map.of("wordsPerMinute", defaultReadingSpeed));
    }

    /**
     * Preview orphaned content images cleanup (dry run)
     */
    @PostMapping("/cleanup/images/preview")
    public ResponseEntity<Map<String, Object>> previewImageCleanup() {
        try {
            logger.info("Starting image cleanup preview");
            ImageService.ContentImageCleanupResult result = imageService.cleanupOrphanedContentImages(true);

            // Create detailed file information with story relationships
            logger.info("Processing {} orphaned files for detailed information", result.getOrphanedImages().size());
            List<Map<String, Object>> orphanedFiles = result.getOrphanedImages().stream()
                .map(filePath -> {
                    try {
                        return createFileInfo(filePath);
                    } catch (Exception e) {
                        logger.error("Error processing file {}: {}", filePath, e.getMessage());
                        // Return a basic error entry instead of failing completely
                        Map<String, Object> errorEntry = new HashMap<>();
                        errorEntry.put("filePath", filePath);
                        errorEntry.put("fileName", Paths.get(filePath).getFileName().toString());
                        errorEntry.put("fileSize", 0L);
                        errorEntry.put("formattedSize", "0 B");
                        errorEntry.put("storyId", "error");
                        errorEntry.put("storyTitle", null);
                        errorEntry.put("storyExists", false);
                        errorEntry.put("canAccessStory", false);
                        errorEntry.put("error", e.getMessage());
                        return errorEntry;
                    }
                })
                .toList();

            // Use HashMap to avoid Map.of() null value issues
            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("orphanedCount", result.getOrphanedImages().size());
            response.put("totalSizeBytes", result.getTotalSizeBytes());
            response.put("formattedSize", result.getFormattedSize());
            response.put("foldersToDelete", result.getFoldersToDelete());
            response.put("referencedImagesCount", result.getTotalReferencedImages());
            response.put("errors", result.getErrors());
            response.put("hasErrors", result.hasErrors());
            response.put("dryRun", true);
            response.put("orphanedFiles", orphanedFiles);

            logger.info("Image cleanup preview completed successfully");
            return ResponseEntity.ok(response);

        } catch (Exception e) {
            logger.error("Failed to preview image cleanup", e);
            Map<String, Object> errorResponse = new HashMap<>();
            errorResponse.put("success", false);
            errorResponse.put("error", "Failed to preview image cleanup: " + (e.getMessage() != null ? e.getMessage() : e.getClass().getSimpleName()));
            return ResponseEntity.status(500).body(errorResponse);
        }
    }

    /**
     * Execute orphaned content images cleanup
     */
    @PostMapping("/cleanup/images/execute")
    public ResponseEntity<Map<String, Object>> executeImageCleanup() {
        try {
            ImageService.ContentImageCleanupResult result = imageService.cleanupOrphanedContentImages(false);

            Map<String, Object> response = Map.of(
                "success", true,
                "deletedCount", result.getOrphanedImages().size(),
                "totalSizeBytes", result.getTotalSizeBytes(),
                "formattedSize", result.getFormattedSize(),
                "foldersDeleted", result.getFoldersToDelete(),
                "referencedImagesCount", result.getTotalReferencedImages(),
                "errors", result.getErrors(),
                "hasErrors", result.hasErrors(),
                "dryRun", false
            );

            return ResponseEntity.ok(response);

        } catch (Exception e) {
            return ResponseEntity.status(500).body(Map.of(
                "success", false,
                "error", "Failed to execute image cleanup: " + e.getMessage()
            ));
        }
    }

    /**
     * Preview migration of flat EPUB content images into story subfolders (dry run)
     */
    @PostMapping("/migrate/epub-images/preview")
    public ResponseEntity<Map<String, Object>> previewEpubImageMigration() {
        try {
            logger.info("Starting EPUB image migration preview");
            ImageService.EpubImageMigrationResult result = imageService.migrateEpubContentImages(true);

            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("movedCount", result.getMovedCount());
            response.put("unmatchedCount", result.getUnmatchedCount());
            response.put("errors", result.getErrors());
            response.put("hasErrors", result.hasErrors());
            response.put("dryRun", true);
            response.put("movedFiles", result.getMovedFiles());

            logger.info("EPUB image migration preview completed: {} to move, {} unmatched",
                result.getMovedCount(), result.getUnmatchedCount());
            return ResponseEntity.ok(response);

        } catch (Exception e) {
            logger.error("Failed to preview EPUB image migration", e);
            Map<String, Object> errorResponse = new HashMap<>();
            errorResponse.put("success", false);
            errorResponse.put("error", "Failed to preview migration: " + (e.getMessage() != null ? e.getMessage() : e.getClass().getSimpleName()));
            return ResponseEntity.status(500).body(errorResponse);
        }
    }

    /**
     * Execute migration of flat EPUB content images into story subfolders
     */
    @PostMapping("/migrate/epub-images/execute")
    public ResponseEntity<Map<String, Object>> executeEpubImageMigration() {
        try {
            logger.info("Starting EPUB image migration execution");
            ImageService.EpubImageMigrationResult result = imageService.migrateEpubContentImages(false);

            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("movedCount", result.getMovedCount());
            response.put("unmatchedCount", result.getUnmatchedCount());
            response.put("errors", result.getErrors());
            response.put("hasErrors", result.hasErrors());
            response.put("dryRun", false);
            response.put("movedFiles", result.getMovedFiles());

            logger.info("EPUB image migration completed: {} moved, {} unmatched, {} errors",
                result.getMovedCount(), result.getUnmatchedCount(), result.getErrors().size());
            return ResponseEntity.ok(response);

        } catch (Exception e) {
            logger.error("Failed to execute EPUB image migration", e);
            Map<String, Object> errorResponse = new HashMap<>();
            errorResponse.put("success", false);
            errorResponse.put("error", "Failed to execute migration: " + (e.getMessage() != null ? e.getMessage() : e.getClass().getSimpleName()));
            return ResponseEntity.status(500).body(errorResponse);
        }
    }

    /**
     * Create detailed file information for orphaned image including story relationship
     */
    private Map<String, Object> createFileInfo(String filePath) {
        try {
            Path path = Paths.get(filePath);
            String fileName = path.getFileName().toString();
            long fileSize = Files.exists(path) ? Files.size(path) : 0;

            // Extract story UUID from the path (content images are stored in /content/{storyId}/)
            String storyId = extractStoryIdFromPath(filePath);

            // Look up the story if we have a valid UUID
            Story relatedStory = null;
            if (storyId != null) {
                try {
                    UUID storyUuid = UUID.fromString(storyId);
                    relatedStory = storyService.findById(storyUuid);
                } catch (Exception e) {
                    logger.debug("Could not find story with ID {}: {}", storyId, e.getMessage());
                }
            }

            Map<String, Object> fileInfo = new HashMap<>();
            fileInfo.put("filePath", filePath);
            fileInfo.put("fileName", fileName);
            fileInfo.put("fileSize", fileSize);
            fileInfo.put("formattedSize", formatBytes(fileSize));
            fileInfo.put("storyId", storyId != null ? storyId : "unknown");
            fileInfo.put("storyTitle", relatedStory != null ? relatedStory.getTitle() : null);
            fileInfo.put("storyExists", relatedStory != null);
            fileInfo.put("canAccessStory", relatedStory != null);

            return fileInfo;
        } catch (Exception e) {
            logger.error("Error creating file info for {}: {}", filePath, e.getMessage());
            Map<String, Object> errorInfo = new HashMap<>();
            errorInfo.put("filePath", filePath);
            errorInfo.put("fileName", Paths.get(filePath).getFileName().toString());
            errorInfo.put("fileSize", 0L);
            errorInfo.put("formattedSize", "0 B");
            errorInfo.put("storyId", "error");
            errorInfo.put("storyTitle", null);
            errorInfo.put("storyExists", false);
            errorInfo.put("canAccessStory", false);
            errorInfo.put("error", e.getMessage() != null ? e.getMessage() : e.getClass().getSimpleName());
            return errorInfo;
        }
    }

    /**
     * Extract story ID from content image file path
     */
    private String extractStoryIdFromPath(String filePath) {
        try {
            // Content images are stored in: /path/to/uploads/content/{storyId}/filename.ext
            Path path = Paths.get(filePath);
            Path parent = path.getParent();
            if (parent != null) {
                String potentialUuid = parent.getFileName().toString();
                // Basic UUID validation (36 characters with dashes in right places)
                if (potentialUuid.length() == 36 &&
                    potentialUuid.charAt(8) == '-' &&
                    potentialUuid.charAt(13) == '-' &&
                    potentialUuid.charAt(18) == '-' &&
                    potentialUuid.charAt(23) == '-') {
                    return potentialUuid;
                }
            }
        } catch (Exception e) {
            // Invalid path or other error
        }
        return null;
    }

    /**
     * Format file size in human readable format
     */
    private String formatBytes(long bytes) {
        if (bytes < 1024) return bytes + " B";
        if (bytes < 1024 * 1024) return String.format("%.1f KB", bytes / 1024.0);
        if (bytes < 1024 * 1024 * 1024) return String.format("%.1f MB", bytes / (1024.0 * 1024.0));
        return String.format("%.1f GB", bytes / (1024.0 * 1024.0 * 1024.0));
    }
}