package at.procon.ted.controller;

import at.procon.dip.domain.document.EmbeddingStatus;
import at.procon.dip.domain.document.repository.DocumentEmbeddingRepository;
import at.procon.ted.config.TedProcessorProperties;
import at.procon.ted.model.entity.ProcessingLog;
import at.procon.ted.model.entity.VectorizationStatus;
import at.procon.ted.repository.ProcurementDocumentRepository;
import at.procon.ted.service.DocumentProcessingService;
import at.procon.ted.service.VectorizationService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import at.procon.dip.runtime.condition.ConditionalOnRuntimeMode;
import at.procon.dip.runtime.config.RuntimeMode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.camel.ProducerTemplate;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.time.OffsetDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * REST API controller for administrative operations.
 * 
 * Provides endpoints for:
 * - System health checks
 * - Manual vectorization triggers
 * - Processing log access
 * - Document reprocessing
 * 
 * @author Martin.Schweitzer@procon.co.at and claude.ai
 */
@RestController
@ConditionalOnRuntimeMode(RuntimeMode.LEGACY)
@RequestMapping("/v1/admin")
@RequiredArgsConstructor
@Slf4j
@Tag(name = "Admin", description = "Administrative Operations API")
public class AdminController {

    private final VectorizationService vectorizationService;
    private final DocumentProcessingService documentProcessingService;
    private final ProcurementDocumentRepository documentRepository;
    private final DocumentEmbeddingRepository documentEmbeddingRepository;
    private final TedProcessorProperties properties;
    private final at.procon.ted.service.TedPhase2GenericDocumentService tedPhase2GenericDocumentService;
    private final at.procon.ted.repository.ProcessingLogRepository logRepository;
    private final ProducerTemplate producerTemplate;
    private final at.procon.ted.service.DataCleanupService dataCleanupService;

    /**
     * Health check endpoint.
     */
    @GetMapping("/health")
    @Operation(summary = "Health check", description = "Check system health and service availability")
    public ResponseEntity<Map<String, Object>> healthCheck() {
        Map<String, Object> health = new HashMap<>();
        health.put("status", "UP");
        health.put("timestamp", OffsetDateTime.now());
        health.put("vectorizationAvailable", vectorizationService.isAvailable());
        health.put("documentCount", documentRepository.count());
        
        return ResponseEntity.ok(health);
    }

    /**
     * Get vectorization status overview.
     */
    @GetMapping("/vectorization/status")
    @Operation(summary = "Vectorization status", description = "Get overview of document vectorization status")
    public ResponseEntity<Map<String, Object>> getVectorizationStatus() {
        Map<String, Object> status = new HashMap<>();
        
        Map<String, Long> statusCounts = new HashMap<>();
        List<Object[]> counts = documentRepository.countByVectorizationStatus();
        for (Object[] row : counts) {
            statusCounts.put(((VectorizationStatus) row[0]).name(), (Long) row[1]);
        }

        
        status.put("counts", statusCounts);
        status.put("serviceAvailable", vectorizationService.isAvailable());
        status.put("timestamp", OffsetDateTime.now());
        
        return ResponseEntity.ok(status);
    }

    /**
     * Manually trigger vectorization for a specific document.
     */
    @PostMapping("/vectorization/trigger/{documentId}")
    @Operation(summary = "Trigger vectorization", description = "Manually trigger vectorization for a specific document")
    public ResponseEntity<Map<String, Object>> triggerVectorization(@PathVariable UUID documentId) {
        Map<String, Object> result = new HashMap<>();

        if (!vectorizationService.isAvailable()) {
            result.put("success", false);
            result.put("message", "Vectorization service is not available");
            return ResponseEntity.badRequest().body(result);
        }

        // Verify document exists
        if (!documentRepository.existsById(documentId)) {
            result.put("success", false);
            result.put("message", "Document not found: " + documentId);
            return ResponseEntity.badRequest().body(result);
        }

        producerTemplate.sendBodyAndHeader("direct:vectorize", null, "documentId", documentId);

        result.put("success", true);
        result.put("message", "Vectorization triggered for document " + documentId);
        result.put("documentId", documentId);

        return ResponseEntity.ok(result);
    }

    /**
     * Trigger vectorization for all pending documents.
     */
    @PostMapping("/vectorization/process-pending")
    @Operation(summary = "Process pending vectorizations", description = "Trigger vectorization for all pending documents")
    public ResponseEntity<Map<String, Object>> processPendingVectorizations(
            @RequestParam(required = false, defaultValue = "100") Integer batchSize) {
        Map<String, Object> result = new HashMap<>();

        if (!vectorizationService.isAvailable()) {
            result.put("success", false);
            result.put("message", "Vectorization service is not available");
            return ResponseEntity.badRequest().body(result);
        }

        int count = 0;
        var pending = documentRepository.findByVectorizationStatus(
                VectorizationStatus.PENDING,
                PageRequest.of(0, Math.min(batchSize, 500)));

        for (var doc : pending) {
            producerTemplate.sendBodyAndHeader("direct:vectorize", null, "documentId", doc.getId());
            count++;
        }

        result.put("success", true);
        result.put("message", "Triggered vectorization for " + count + " documents");
        result.put("documentsQueued", count);

        return ResponseEntity.ok(result);
    }

    /**
     * Reprocess a document by publication ID.
     */
    @PostMapping("/reprocess/{publicationId}")
    @Operation(summary = "Reprocess document", description = "Reparse and revectorize a document by publication ID")
    public ResponseEntity<Map<String, Object>> reprocessDocument(@PathVariable String publicationId) {
        Map<String, Object> result = new HashMap<>();
        
        var updated = documentProcessingService.reprocessDocument(publicationId);
        
        if (updated.isPresent()) {
            result.put("success", true);
            result.put("message", "Document reprocessed successfully");
            result.put("documentId", updated.get().getId());
            result.put("publicationId", publicationId);
            return ResponseEntity.ok(result);
        } else {
            result.put("success", false);
            result.put("message", "Document not found or reprocessing failed");
            result.put("publicationId", publicationId);
            return ResponseEntity.notFound().build();
        }
    }

    /**
     * Get recent processing logs.
     */
    @GetMapping("/logs/recent")
    @Operation(summary = "Recent processing logs", description = "Get recent document processing log entries")
    public ResponseEntity<List<ProcessingLog>> getRecentLogs(
            @RequestParam(required = false, defaultValue = "24") Integer hoursBack,
            @RequestParam(required = false, defaultValue = "100") Integer limit) {
        
        OffsetDateTime since = OffsetDateTime.now().minusHours(hoursBack);
        List<ProcessingLog> logs = logRepository.findRecentLogs(since);
        
        if (logs.size() > limit) {
            logs = logs.subList(0, limit);
        }
        
        return ResponseEntity.ok(logs);
    }

    /**
     * Get processing logs for a specific document.
     */
    @GetMapping("/logs/document/{documentId}")
    @Operation(summary = "Document processing logs", description = "Get processing log entries for a specific document")
    public ResponseEntity<List<ProcessingLog>> getDocumentLogs(@PathVariable UUID documentId) {
        List<ProcessingLog> logs = logRepository.findByDocumentIdOrderByCreatedAtDesc(documentId);
        return ResponseEntity.ok(logs);
    }

    /**
     * Get system information.
     */
    @GetMapping("/info")
    @Operation(summary = "System information", description = "Get system configuration and runtime information")
    public ResponseEntity<Map<String, Object>> getSystemInfo() {
        Map<String, Object> info = new HashMap<>();
        
        info.put("javaVersion", System.getProperty("java.version"));
        info.put("osName", System.getProperty("os.name"));
        info.put("availableProcessors", Runtime.getRuntime().availableProcessors());
        info.put("maxMemory", Runtime.getRuntime().maxMemory());
        info.put("freeMemory", Runtime.getRuntime().freeMemory());
        info.put("totalMemory", Runtime.getRuntime().totalMemory());
        info.put("vectorizationEnabled", vectorizationService.isAvailable());

        return ResponseEntity.ok(info);
    }

    /**
     * Count documents older than specified retention period.
     */
    @GetMapping("/cleanup/count")
    @Operation(summary = "Count old documents", description = "Count documents older than specified years")
    public ResponseEntity<Map<String, Object>> countOldDocuments(
            @RequestParam(required = false, defaultValue = "7") Integer years) {
        Map<String, Object> result = new HashMap<>();

        long count = dataCleanupService.countDocumentsOlderThan(years);

        result.put("years", years);
        result.put("count", count);
        result.put("message", String.format("Found %d documents older than %d years", count, years));

        return ResponseEntity.ok(result);
    }

    /**
     * Delete documents older than specified retention period.
     */
    @DeleteMapping("/cleanup/delete")
    @Operation(summary = "Delete old documents", description = "Delete documents older than specified years (default: 7)")
    public ResponseEntity<Map<String, Object>> deleteOldDocuments(
            @RequestParam(required = false, defaultValue = "7") Integer years) {
        Map<String, Object> result = new HashMap<>();

        try {
            int deletedCount = dataCleanupService.deleteDocumentsOlderThan(years);

            result.put("success", true);
            result.put("years", years);
            result.put("deletedCount", deletedCount);
            result.put("message", String.format("Deleted %d documents older than %d years", deletedCount, years));

            return ResponseEntity.ok(result);

        } catch (Exception e) {
            log.error("Error deleting old documents", e);
            result.put("success", false);
            result.put("error", e.getMessage());
            return ResponseEntity.status(500).body(result);
        }
    }
}
