package kz.konturai.parser.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;

import java.io.InputStream;

public class SvgToPngConverter {

    // Регулярные выражения для поиска и исправления отрицательных значений
    private static final Pattern HEIGHT_PATTERN = Pattern.compile("height\\s*=\\s*[\"']([^\"']*)[\"']");
    private static final Pattern WIDTH_PATTERN = Pattern.compile("width\\s*=\\s*[\"']([^\"']*)[\"']");
    private static final Pattern Y_PATTERN = Pattern.compile("y\\s*=\\s*[\"']([^\"']*)[\"']");
    private static final Pattern X_PATTERN = Pattern.compile("x\\s*=\\s*[\"']([^\"']*)[\"']");
    private static final Pattern R_PATTERN = Pattern.compile("r\\s*=\\s*[\"']([^\"']*)[\"']");

    /**
     * Преобразует строку с SVG-кодом в массив байт PNG-изображения.
     * 
     * @param svgCode Строка, содержащая валидный SVG.
     * @return Массив байт PNG или null в случае ошибки.
     */
    public static byte[] convert(String svgCode) {
        if (svgCode == null || svgCode.isBlank()) {
            return null;
        }

        try {
            // 1. Санитизируем SVG код перед конвертацией
            String sanitizedSvg = sanitizeSvg(svgCode);

            // 2. Создаем транскодер для PNG с улучшенными настройками
            PNGTranscoder transcoder = new PNGTranscoder();

            // Устанавливаем размеры для оптимального качества в PDF
            // Если SVG не имеет явных размеров, устанавливаем стандартные
            if (!sanitizedSvg.contains("width=") || !sanitizedSvg.contains("height=")) {
                transcoder.addTranscodingHint(PNGTranscoder.KEY_WIDTH, 800f);
                transcoder.addTranscodingHint(PNGTranscoder.KEY_HEIGHT, 600f);
            }

            // 3. Устанавливаем входные данные (наш SVG-код)
            InputStream inputStream = new ByteArrayInputStream(sanitizedSvg.getBytes(StandardCharsets.UTF_8));
            TranscoderInput input = new TranscoderInput(inputStream);

            // 4. Устанавливаем, куда будет записан результат (в байтовый массив в памяти)
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            TranscoderOutput output = new TranscoderOutput(outputStream);

            // 5. Запускаем процесс конвертации
            transcoder.transcode(input, output);

            // 6. Получаем результат
            outputStream.flush();
            return outputStream.toByteArray();

        } catch (Exception e) {
            System.err.println("Ошибка при конвертации SVG в PNG: " + e.getMessage());
            e.printStackTrace(); // Очень полезно для отладки
            return null;
        }
    }

    /**
     * Санитизирует SVG код, исправляя отрицательные значения в атрибутах.
     * 
     * @param svgCode Исходный SVG код
     * @return Санитизированный SVG код
     */
    private static String sanitizeSvg(String svgCode) {
        if (svgCode == null || svgCode.isBlank()) {
            return svgCode;
        }

        String result = svgCode;

        // Исправляем отрицательные значения height
        result = fixNegativeValues(result, HEIGHT_PATTERN, "height");

        // Исправляем отрицательные значения width
        result = fixNegativeValues(result, WIDTH_PATTERN, "width");

        // Исправляем отрицательные значения y
        result = fixNegativeValues(result, Y_PATTERN, "y");

        // Исправляем отрицательные значения x
        result = fixNegativeValues(result, X_PATTERN, "x");

        // Исправляем отрицательные значения r (радиус)
        result = fixNegativeValues(result, R_PATTERN, "r");

        return result;
    }

    /**
     * Исправляет отрицательные значения в указанном атрибуте.
     * 
     * @param svgCode       SVG код
     * @param pattern       Регулярное выражение для поиска атрибута
     * @param attributeName Название атрибута для логирования
     * @return Исправленный SVG код
     */
    private static String fixNegativeValues(String svgCode, Pattern pattern, String attributeName) {
        Matcher matcher = pattern.matcher(svgCode);
        StringBuffer result = new StringBuffer();

        while (matcher.find()) {
            String value = matcher.group(1);
            try {
                // Пытаемся распарсить значение как число
                double numValue = Double.parseDouble(value.trim());
                if (numValue < 0) {
                    // Заменяем отрицательное значение на 0
                    String replacement = matcher.group(0).replace(value, "0");
                    matcher.appendReplacement(result, replacement);
                    System.out.println("Исправлено отрицательное значение " + attributeName + ": " + value + " -> 0");
                } else {
                    matcher.appendReplacement(result, matcher.group(0));
                }
            } catch (NumberFormatException e) {
                // Если не удается распарсить как число, оставляем как есть
                matcher.appendReplacement(result, matcher.group(0));
            }
        }
        matcher.appendTail(result);

        return result.toString();
    }
}