package kz.konturai.parser.service;

import com.lowagie.text.*;
import com.lowagie.text.pdf.BaseFont;
import com.lowagie.text.pdf.ColumnText;
import com.lowagie.text.pdf.PdfWriter;
import kz.konturai.parser.dto.DeepResearchResponse;
import org.springframework.stereotype.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayOutputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

import com.lowagie.text.pdf.PdfPageEventHelper;

import java.awt.Color; // УБЕДИТЕСЬ, ЧТО ИМПОРТИРОВАН java.awt.Color

import java.io.InputStream;

@Service
public class ResearchPdfService {

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

    // --- Шрифты с поддержкой кириллицы ---
    private final BaseFont baseFont;
    private final Font titleFont;
    private final Font headingFont;
    private final Font subheadingFont;
    private final Font normalFont;
    private final Font smallFont;
    private final Font linkFont;
    private final Font footerFont;

    public ResearchPdfService() {
        BaseFont resolvedBaseFont;
        try {
            InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("fonts/DejaVuSans.ttf");
            if (is == null) {
                throw new RuntimeException("Font file fonts/DejaVuSans.ttf not found in classpath.");
            }
            try (is) {
                byte[] fontBytes = is.readAllBytes();
                resolvedBaseFont = BaseFont.createFont("DejaVuSans.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED, false,
                        fontBytes, null);
            }
        } catch (Exception e) {
            // Фолбэк на стандартный шрифт, если DejaVuSans не загрузился
            try {
                resolvedBaseFont = BaseFont.createFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.NOT_EMBEDDED);
                System.err.println(
                        "ResearchPdfService: DejaVuSans.ttf not found. Falling back to Helvetica. Cyrillic may not display correctly.");
            } catch (Exception inner) {
                throw new RuntimeException("Failed to load any font", inner);
            }
        }

        this.baseFont = resolvedBaseFont;
        this.titleFont = new Font(baseFont, 18, Font.BOLD);
        this.headingFont = new Font(baseFont, 14, Font.BOLD);
        this.subheadingFont = new Font(baseFont, 12, Font.BOLD);
        this.normalFont = new Font(baseFont, 10, Font.NORMAL);
        this.smallFont = new Font(baseFont, 8, Font.ITALIC);
        this.footerFont = new Font(baseFont, 8, Font.NORMAL, Color.GRAY);
        // ИСПРАВЛЕНО: Возвращаем синий цвет ссылкам
        this.linkFont = new Font(baseFont, 8, Font.UNDERLINE, Color.BLUE);
    }

    // УЛУЧШЕНО: Внутренний класс для добавления нумерации страниц
    private static class PageFooter extends PdfPageEventHelper {
        private final Font font;

        public PageFooter(Font font) {
            this.font = font;
        }

        @Override
        public void onEndPage(PdfWriter writer, Document document) {
            if (document.getPageNumber() > 1) { // Не добавляем номер на титульную страницу
                ColumnText.showTextAligned(writer.getDirectContent(),
                        Element.ALIGN_CENTER,
                        new Phrase(String.format("Страница %d", writer.getPageNumber()), font),
                        (document.right() - document.left()) / 2 + document.leftMargin(),
                        document.bottom() - 10, 0);
            }
        }
    }

    public byte[] generatePdfReport(String query, DeepResearchResponse researchResponse) {
        try {
            String mainContent = researchResponse == null ? null : researchResponse.getMainContent();
            java.util.List<String> urls = researchResponse == null ? null : researchResponse.getVisitedUrls();
            int contentLength = mainContent == null ? 0 : mainContent.length();
            int urlCount = urls == null ? 0 : urls.size();
            logger.info("PDF input (legacy): query='{}', contentLength={}, visitedUrlsCount={}", query, contentLength,
                    urlCount);
            // if (logger.isDebugEnabled()) {
            logger.info("PDF input (legacy) full content:\n{}", mainContent);
            logger.info("PDF input (legacy) visitedUrls: {}", urls);
            // }
        } catch (Exception logEx) {
            // do not fail generation due to logging issue
        }
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            Document document = new Document(PageSize.A4, 36, 36, 36, 54); // Добавлены отступы
            PdfWriter writer = PdfWriter.getInstance(document, outputStream);

            // УЛУЧШЕНО: Устанавливаем обработчик событий для нумерации страниц
            writer.setPageEvent(new PageFooter(footerFont));

            document.addTitle(query);
            document.addAuthor("AI Research Agent");
            document.addSubject("Research Report");

            document.open();

            addTitlePage(document, query);
            addMainReport(document, researchResponse);
            addSources(document, researchResponse.getVisitedUrls());

            document.close();
            return outputStream.toByteArray();
        } catch (Exception e) {
            throw new RuntimeException("Failed to generate PDF report", e);
        }
    }

    public byte[] generatePdfReport(String query, String synthesizedMarkdown, java.util.List<String> visitedUrls) {
        try {
            int contentLength = synthesizedMarkdown == null ? 0 : synthesizedMarkdown.length();
            int urlCount = visitedUrls == null ? 0 : visitedUrls.size();
            logger.info("PDF input (synthesized): query='{}', contentLength={}, visitedUrlsCount={}", query,
                    contentLength, urlCount);
            // if (logger.isDebugEnabled()) {
            logger.info("PDF input (synthesized) full content:\n{}", synthesizedMarkdown);
            logger.info("PDF input (synthesized) visitedUrls: {}", visitedUrls);
            // }
        } catch (Exception logEx) {
            // do not fail generation due to logging issue
        }
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            Document document = new Document(PageSize.A4, 36, 36, 36, 54);
            PdfWriter writer = PdfWriter.getInstance(document, outputStream);

            writer.setPageEvent(new PageFooter(footerFont));

            document.addTitle(query);
            document.addAuthor("AI Research Agent");
            document.addSubject("Research Report");

            document.open();

            addTitlePage(document, query);
            addMainReportFromMarkdown(document, synthesizedMarkdown);
            addSources(document, visitedUrls);

            document.close();
            return outputStream.toByteArray();
        } catch (Exception e) {
            throw new RuntimeException("Failed to generate PDF report (synthesized)", e);
        }
    }

    public byte[] generatePdfReport(String query, String synthesizedMarkdown, java.util.List<String> visitedUrls,
            java.util.List<byte[]> chartImages) {
        try {
            int contentLength = synthesizedMarkdown == null ? 0 : synthesizedMarkdown.length();
            int urlCount = visitedUrls == null ? 0 : visitedUrls.size();
            int charts = chartImages == null ? 0 : chartImages.size();
            logger.info("PDF input (with charts): query='{}', contentLength={}, visitedUrlsCount={}, charts={}", query,
                    contentLength, urlCount, charts);
        } catch (Exception logEx) {
        }
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            Document document = new Document(PageSize.A4, 36, 36, 36, 54);
            PdfWriter writer = PdfWriter.getInstance(document, outputStream);

            writer.setPageEvent(new PageFooter(footerFont));

            document.addTitle(query);
            document.addAuthor("AI Research Agent");
            document.addSubject("Research Report");

            document.open();

            addTitlePage(document, query);
            addMainReportFromMarkdown(document, synthesizedMarkdown);
            addChartsSection(document, chartImages);
            addSources(document, visitedUrls);

            document.close();
            return outputStream.toByteArray();
        } catch (Exception e) {
            throw new RuntimeException("Failed to generate PDF report (with charts)", e);
        }
    }

    private void addChartsSection(Document document, java.util.List<byte[]> chartImages) throws DocumentException {
        if (chartImages == null || chartImages.isEmpty()) {
            return;
        }

        document.newPage();
        Paragraph title = new Paragraph("Визуализация данных", headingFont);
        Chapter chapter = new Chapter(title, 3);
        chapter.setNumberDepth(0);

        for (int i = 0; i < chartImages.size(); i++) {
            try {
                Image chartImage = Image.getInstance(chartImages.get(i));

                // --- УЛУЧШЕННАЯ ЛОГИКА МАСШТАБИРОВАНИЯ ---
                float pageWidth = document.getPageSize().getWidth();
                float pageHeight = document.getPageSize().getHeight();
                float leftMargin = document.leftMargin();
                float rightMargin = document.rightMargin();
                float topMargin = document.topMargin();
                float bottomMargin = document.bottomMargin();

                // Рассчитываем доступное пространство с учетом отступов
                float availableWidth = pageWidth - leftMargin - rightMargin;
                float availableHeight = pageHeight - topMargin - bottomMargin - 80; // -80 для заголовков и отступов

                // Получаем оригинальные размеры изображения
                float originalWidth = chartImage.getWidth();
                float originalHeight = chartImage.getHeight();

                // Рассчитываем коэффициенты масштабирования
                float scaleX = availableWidth / originalWidth;
                float scaleY = availableHeight / originalHeight;

                // Используем меньший коэффициент для сохранения пропорций
                float scale = Math.min(scaleX, scaleY);

                // Ограничиваем масштабирование для читаемости
                scale = Math.min(scale, 1.0f); // Не увеличиваем больше оригинала
                scale = Math.max(scale, 0.3f); // Не уменьшаем слишком сильно

                // Применяем масштабирование
                chartImage.scalePercent(scale * 100);

                // Проверяем, помещается ли диаграмма на страницу
                float scaledWidth = chartImage.getScaledWidth();
                float scaledHeight = chartImage.getScaledHeight();

                // Если диаграмма все еще слишком большая, принудительно уменьшаем
                if (scaledWidth > availableWidth || scaledHeight > availableHeight) {
                    float forceScaleX = availableWidth / scaledWidth;
                    float forceScaleY = availableHeight / scaledHeight;
                    float forceScale = Math.min(forceScaleX, forceScaleY) * 0.9f; // 90% для безопасности
                    chartImage.scalePercent(forceScale * 100);
                }

                // Центрируем изображение
                chartImage.setAlignment(Element.ALIGN_CENTER);

                // Добавляем отступы для лучшего внешнего вида
                chartImage.setSpacingBefore(20);
                chartImage.setSpacingAfter(20);

                // Добавляем подпись к диаграмме
                if (chartImages.size() > 1) {
                    Paragraph chartTitle = new Paragraph("Диаграмма " + (i + 1), subheadingFont);
                    chartTitle.setAlignment(Element.ALIGN_CENTER);
                    chartTitle.setSpacingBefore(10);
                    chapter.add(chartTitle);
                }

                // Используем новую логику добавления с разбиением на страницы
                addChartWithPagination(chartImage, chapter, document, i);

                // Добавляем разрыв страницы между диаграммами, если их много
                if (i < chartImages.size() - 1) {
                    chapter.add(Chunk.NEWLINE);
                    chapter.add(Chunk.NEWLINE);
                }

            } catch (Exception e) {
                System.err.println("Не удалось добавить изображение диаграммы в PDF: " + e.getMessage());
                logger.error("Error adding chart image to PDF", e);
            }
        }
        document.add(chapter);
    }

    /**
     * Проверяет, нужно ли разбивать диаграмму на несколько страниц
     */
    private boolean shouldSplitChart(Image chartImage, Document document) {
        float pageHeight = document.getPageSize().getHeight();
        float topMargin = document.topMargin();
        float bottomMargin = document.bottomMargin();
        float availableHeight = pageHeight - topMargin - bottomMargin - 80;

        return chartImage.getScaledHeight() > availableHeight * 0.8f; // 80% от доступной высоты
    }

    /**
     * Добавляет диаграмму с возможным разбиением на страницы
     */
    private void addChartWithPagination(Image chartImage, Chapter chapter, Document document, int chartIndex)
            throws DocumentException {
        if (shouldSplitChart(chartImage, document)) {
            // Если диаграмма слишком большая, добавляем ее на отдельную страницу
            document.newPage();
            Paragraph chartTitle = new Paragraph("Диаграмма " + (chartIndex + 1) + " (продолжение)", subheadingFont);
            chartTitle.setAlignment(Element.ALIGN_CENTER);
            chartTitle.setSpacingBefore(10);
            chapter.add(chartTitle);
        }

        chapter.add(new Paragraph(" ")); // Отступ
        chapter.add(chartImage);
    }

    private void addTitlePage(Document document, String query) throws DocumentException {
        // Этот метод был в порядке, оставляем без изменений
        Paragraph title = new Paragraph(query, titleFont);
        title.setAlignment(Element.ALIGN_CENTER);
        title.setSpacingBefore(50);
        title.setSpacingAfter(50);
        document.add(title);

        Paragraph subtitle = new Paragraph("Автоматизированный исследовательский отчёт", headingFont);
        subtitle.setAlignment(Element.ALIGN_CENTER);
        subtitle.setSpacingAfter(30);
        document.add(subtitle);

        String currentDate = LocalDateTime.now().format(DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm"));
        Paragraph date = new Paragraph("Дата создания: " + currentDate, normalFont);
        date.setAlignment(Element.ALIGN_CENTER);
        date.setSpacingAfter(100);
        document.add(date);
    }

    private String cleanContent(String rawContent) {
        if (rawContent == null) {
            return "";
        }
        // Нормализуем переносы строк, избегая некорректных regex-замен
        String normalized = rawContent.replace("\r\n", "\n").replace("\r", "\n");
        return normalized.trim();
    }

    private void addMainReport(Document document, DeepResearchResponse researchResponse) throws DocumentException {
        String cleanedContent = cleanContent(researchResponse.getMainContent());
        if (cleanedContent.isEmpty()) {
            cleanedContent = "## Отчёт не был сгенерирован.\n\nДанные для анализа отсутствуют.";
        }

        document.newPage();

        String[] lines = cleanedContent.split("\n");
        Chapter chapter = new Chapter(new Paragraph("Основной отчёт", headingFont), 1);
        chapter.setNumberDepth(0); // Скрываем номер главы "1."

        // ИСПРАВЛЕНО: Логика обработки списков
        com.lowagie.text.List currentList = null;

        for (String line : lines) {
            if (line.trim().isEmpty())
                continue;

            // Если текущая строка не является элементом списка, а мы были в списке,
            // то завершаем старый список
            if (!(line.startsWith("- ") || line.startsWith("* ")) && currentList != null) {
                chapter.add(currentList);
                currentList = null;
            }

            if (line.startsWith("# ")) {
                chapter.add(new Paragraph(line.substring(2), headingFont));
            } else if (line.startsWith("## ")) {
                chapter.add(new Paragraph(line.substring(3), subheadingFont));
            } else if (line.startsWith("- ") || line.startsWith("* ")) {
                // Если мы еще не в списке, создаем новый
                if (currentList == null) {
                    currentList = new com.lowagie.text.List(com.lowagie.text.List.UNORDERED);
                    currentList.setListSymbol(new Chunk("- ", normalFont));
                }
                currentList.add(new ListItem(line.substring(2), normalFont));
            } else {
                Paragraph para = new Paragraph(line, normalFont);
                para.setSpacingAfter(10);
                chapter.add(para);
            }
        }

        // Добавляем последний список, если он остался
        if (currentList != null) {
            chapter.add(currentList);
        }

        document.add(chapter);
    }

    private void addMainReportFromMarkdown(Document document, String markdown) throws DocumentException {
        String cleanedContent = cleanContent(markdown);
        if (cleanedContent == null || cleanedContent.isEmpty()) {
            cleanedContent = "## Отчёт не был сгенерирован.\n\nДанные для анализа отсутствуют.";
        }

        document.newPage();

        String[] lines = cleanedContent.split("\n");
        Chapter chapter = new Chapter(new Paragraph("Основной отчёт", headingFont), 1);
        chapter.setNumberDepth(0);

        com.lowagie.text.List currentList = null;

        for (String line : lines) {
            if (line.trim().isEmpty())
                continue;
            if (!(line.startsWith("- ") || line.startsWith("* ")) && currentList != null) {
                chapter.add(currentList);
                currentList = null;
            }
            if (line.startsWith("# ")) {
                chapter.add(new Paragraph(line.substring(2), headingFont));
            } else if (line.startsWith("## ")) {
                chapter.add(new Paragraph(line.substring(3), subheadingFont));
            } else if (line.startsWith("- ") || line.startsWith("* ")) {
                if (currentList == null) {
                    currentList = new com.lowagie.text.List(com.lowagie.text.List.UNORDERED);
                    currentList.setListSymbol(new Chunk("- ", normalFont));
                }
                currentList.add(new ListItem(line.substring(2), normalFont));
            } else {
                Paragraph para = new Paragraph(line, normalFont);
                para.setSpacingAfter(10);
                chapter.add(para);
            }
        }

        if (currentList != null) {
            chapter.add(currentList);
        }

        document.add(chapter);
    }

    private void addSources(Document document, List<String> visitedUrls) throws DocumentException {
        document.newPage();
        Paragraph sourcesTitle = new Paragraph("Источники", headingFont);
        Chapter sourcesChapter = new Chapter(sourcesTitle, 2);
        sourcesChapter.setNumberDepth(0); // Скрываем номер

        if (visitedUrls == null || visitedUrls.isEmpty()) {
            sourcesChapter.add(new Paragraph("Источники не были предоставлены.", normalFont));
        } else {
            com.lowagie.text.List list = new com.lowagie.text.List(com.lowagie.text.List.ORDERED);
            for (String url : visitedUrls) {
                Anchor anchor = new Anchor(url, linkFont);
                anchor.setReference(url);
                list.add(new ListItem(anchor));
            }
            sourcesChapter.add(list);
        }
        document.add(sourcesChapter);
    }
}