package kz.konturai.parser.controller;

import kz.konturai.parser.dto.ReportGenerateRequest;
import kz.konturai.parser.dto.FinalReportPayload;
import kz.konturai.parser.dto.ReportGenerationResponse;
import kz.konturai.parser.dto.ApiResponse;
import kz.konturai.parser.dto.ResearchReportRequest;
import kz.konturai.parser.dto.DeepResearchRequest;
import kz.konturai.parser.dto.DeepResearchResponse;
import kz.konturai.parser.model.ReportHistory;
import kz.konturai.parser.repository.ReportHistoryRepository;
import kz.konturai.parser.service.ReportGenerationService;
import kz.konturai.parser.service.DeepResearchService;
import kz.konturai.parser.service.ResearchPdfService;
import kz.konturai.parser.service.ReportSynthesisService;
import kz.konturai.parser.service.MinIOService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.Optional;
import java.time.LocalDateTime;
import java.util.UUID;

import kz.konturai.parser.dto.PageResponse;
import reactor.core.scheduler.Schedulers;

@RestController
@RequestMapping("/api/parser/report")
public class ReportController {

        private final ReportGenerationService reportGenerationService;
        private final ReportHistoryRepository reportHistoryRepository;
        private final MinIOService minIOService;
        private final DeepResearchService deepResearchService;
        private final ResearchPdfService researchPdfService;
        private final ReportSynthesisService reportSynthesisService;

        public ReportController(ReportGenerationService reportGenerationService,
                        ReportHistoryRepository reportHistoryRepository,
                        MinIOService minIOService,
                        DeepResearchService deepResearchService,
                        ResearchPdfService researchPdfService,
                        ReportSynthesisService reportSynthesisService) {
                this.reportGenerationService = reportGenerationService;
                this.reportHistoryRepository = reportHistoryRepository;
                this.minIOService = minIOService;
                this.deepResearchService = deepResearchService;
                this.researchPdfService = researchPdfService;
                this.reportSynthesisService = reportSynthesisService;
        }

        @PostMapping("/generate")
        public ResponseEntity<ApiResponse<ReportGenerationResponse>> generate(
                        @Validated @RequestBody ReportGenerateRequest request) {
                // Generate unique task ID
                String taskId = UUID.randomUUID().toString();

                // Start async report generation
                reportGenerationService.generateAsync(request);

                // Calculate estimated completion time (5-10 minutes for complex reports)
                LocalDateTime estimatedCompletion = LocalDateTime.now().plusMinutes(8);

                ReportGenerationResponse response = new ReportGenerationResponse(
                                taskId,
                                "Отчёт будет сгенерирован в фоновом режиме. Ожидаемое время завершения: "
                                                + estimatedCompletion.format(
                                                                java.time.format.DateTimeFormatter.ofPattern("HH:mm")),
                                estimatedCompletion,
                                "PROCESSING");

                return ResponseEntity.ok(ApiResponse.success("Отчёт поставлен в очередь на генерацию", response));
        }

        @PostMapping
        public ResponseEntity<ApiResponse<ReportGenerationResponse>> generateResearchReport(
                        @Validated @RequestBody ResearchReportRequest request) {
                // Валидация входных данных
                if (request.getQuery() == null || request.getQuery().trim().isEmpty()) {
                        return ResponseEntity.badRequest().build();
                }

                // Подготовка запроса для deep-research API
                DeepResearchRequest deepRequest = new DeepResearchRequest(
                                request.getQuery(),
                                request.getLang(),
                                request.getDepth(),
                                request.getBreadth(),
                                request.getReportType());

                // Генерация уникального ID задачи
                String taskId = UUID.randomUUID().toString();

                // Предполагаемое время завершения
                LocalDateTime estimatedCompletion = LocalDateTime.now().plusMinutes(8);

                // Запускаем асинхронный процесс: deep-research -> synthesis via Ollama -> PDF
                // -> сохранение
                deepResearchService.generateReportAsync(deepRequest)
                                .publishOn(Schedulers.boundedElastic())
                                .flatMap(researchResponse -> {
                                        if (researchResponse == null
                                                        || researchResponse.getLearnings() == null
                                                        || researchResponse.getLearnings().isEmpty()) {
                                                return reactor.core.publisher.Mono.error(
                                                                new RuntimeException(
                                                                                "Empty research response content"));
                                        }
                                        return reportSynthesisService
                                                        .synthesizeReportAndCharts(request.getQuery(),
                                                                        researchResponse.getLearnings(),
                                                                        request.getLang())
                                                        .map(payload -> new Object[] { researchResponse, payload });
                                })
                                .map(tuple -> {
                                        DeepResearchResponse researchResponse = (DeepResearchResponse) tuple[0];
                                        FinalReportPayload payload = (FinalReportPayload) tuple[1];
                                        // --- НОВАЯ ЛОГИКА ЗДЕСЬ ---
                                        StringBuilder finalMarkdown = new StringBuilder();

                                        // 1. Добавляем основной синтезированный отчёт от AI
                                        if (payload.getMarkdownContent() != null) {
                                                finalMarkdown.append(payload.getMarkdownContent());
                                        }

                                        // 2. Добавляем разделитель и новый раздел для "сырых" данных
                                        finalMarkdown.append("\n\n---\n\n");
                                        finalMarkdown.append("## Приложение: Исходные тезисы (Learnings)\n\n");

                                        // 3. Добавляем сами learnings в виде списка
                                        if (researchResponse.getLearnings() != null
                                                        && !researchResponse.getLearnings().isEmpty()) {
                                                for (String learning : researchResponse.getLearnings()) {
                                                        finalMarkdown.append("- ").append(learning).append("\n");
                                                }
                                        } else {
                                                finalMarkdown.append("Исходные тезисы не были найдены.\n");
                                        }
                                        // --- КОНЕЦ НОВОЙ ЛОГИКИ ---

                                        // Теперь в PDF передаётся ОБЪЕДИНЕННЫЙ текст
                                        byte[] pdfBytes = researchPdfService.generatePdfReport(request.getQuery(),
                                                        finalMarkdown.toString(),
                                                        researchResponse.getVisitedUrls(),
                                                        payload.getChartImages());
                                        String filename = "research_report_" + System.currentTimeMillis() + ".pdf";
                                        saveResearchReportToHistory(request, filename, pdfBytes, researchResponse);
                                        return true;
                                })
                                .doOnError(e -> {
                                        System.err.println("Error generating research report async: " + e.getMessage());
                                })
                                .subscribe(
                                                ok -> {
                                                },
                                                err -> {
                                                        // Avoid onErrorDropped by consuming error here
                                                        System.err.println("Async pipeline error: " + err.getMessage());
                                                });

                ReportGenerationResponse response = new ReportGenerationResponse(
                                taskId,
                                "Исследование запущено в фоновом режиме. Ожидаемое время завершения: "
                                                + estimatedCompletion
                                                                .format(java.time.format.DateTimeFormatter.ofPattern(
                                                                                "HH:mm")),
                                estimatedCompletion,
                                "PROCESSING");

                return ResponseEntity.ok(ApiResponse.success("Исследовательский отчёт поставлен в очередь", response));
        }

        private void saveResearchReportToHistory(ResearchReportRequest request, String filename,
                        byte[] pdfBytes, DeepResearchResponse researchResponse) {
                try {
                        // Загрузка в MinIO
                        minIOService.uploadFile(filename, pdfBytes, MediaType.APPLICATION_PDF.toString());

                        // Сохранение в базу данных
                        ReportHistory reportHistory = new ReportHistory();
                        reportHistory.setReportTitle(request.getQuery());
                        reportHistory.setAuthorName("AI Research Agent");
                        reportHistory.setCompanyName("Deep Research Service");
                        reportHistory.setStartDate(LocalDateTime.now());
                        reportHistory.setEndDate(LocalDateTime.now());
                        reportHistory.setFormat("PDF");
                        reportHistory.setFilename(filename);
                        reportHistory.setFilePath(filename);
                        reportHistory.setFileSize(pdfBytes.length);
                        reportHistory.setCreatedAt(LocalDateTime.now());

                        reportHistoryRepository.save(reportHistory);
                } catch (Exception e) {
                        System.err.println("Error saving research report to history: " + e.getMessage());
                        // Не прерываем выполнение, если не удалось сохранить в историю
                }
        }

        @GetMapping("/history")
        public ResponseEntity<PageResponse<ReportHistory>> history(
                        @RequestParam(name = "page", defaultValue = "0") int page,
                        @RequestParam(name = "size", defaultValue = "20") int size,
                        @RequestParam(name = "sort", defaultValue = "createdAt,desc") String sort) {
                String[] parts = sort.split(",");
                String sortField = parts.length > 0 ? parts[0] : "createdAt";
                Sort.Direction dir = parts.length > 1 && parts[1].equalsIgnoreCase("asc") ? Sort.Direction.ASC
                                : Sort.Direction.DESC;
                Pageable pageable = PageRequest.of(page, size, Sort.by(dir, sortField));
                Page<ReportHistory> res = reportHistoryRepository.findAll(pageable);
                PageResponse<ReportHistory> dto = new PageResponse<>(
                                res.getContent(),
                                res.getNumber(),
                                res.getSize(),
                                res.getTotalElements(),
                                res.getTotalPages(),
                                sort);
                return ResponseEntity.ok(dto);
        }

        @GetMapping("/history/{id}")
        public ResponseEntity<byte[]> download(@PathVariable("id") String id) {
                Optional<ReportHistory> opt = reportHistoryRepository.findById(id);
                if (opt.isEmpty()) {
                        return ResponseEntity.notFound().build();
                }
                ReportHistory rh = opt.get();
                try {
                        // Download from MinIO
                        java.io.InputStream inputStream = minIOService.downloadFile(rh.getFilePath());
                        byte[] bytes = inputStream.readAllBytes();
                        inputStream.close();

                        MediaType mt = rh.getFormat() != null && rh.getFormat().equalsIgnoreCase("DOCX")
                                        ? MediaType
                                                        .parseMediaType("application/vnd.openxmlformats-officedocument.wordprocessingml.document")
                                        : MediaType.APPLICATION_PDF;
                        return ResponseEntity.ok()
                                        .header(HttpHeaders.CONTENT_DISPOSITION,
                                                        "attachment; filename=\"" + rh.getFilename() + "\"")
                                        .contentType(mt)
                                        .body(bytes);
                } catch (Exception e) {
                        return ResponseEntity.internalServerError().build();
                }
        }
}
