package de.roko.genalogy.downloader.tools;

import org.openqa.selenium.*;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.time.Duration;
import java.util.*;

public class BookTileDownloader {

    private final WebDriver driver;
    private final JavascriptExecutor js;
    private final WebDriverWait wait;
    private final Actions actions;

    public BookTileDownloader(WebDriver driver) {
        this.driver = driver;
        this.js = (JavascriptExecutor) driver;
        this.wait = new WebDriverWait(driver, Duration.ofSeconds(10));
        this.actions = new Actions(driver);
    }

    private int extractPixel(String style, String property) {
        try {
            for (String part : style.split(";")) {
                part = part.trim();
                if (part.startsWith(property)) {
                    return Integer.parseInt(part.replaceAll("[^0-9]", ""));
                }
            }
        } catch (Exception e) {
            System.err.printf("⚠️ Fehler beim Extrahieren von '%s' aus Style: %s%n", property, style);
        }
        return 0;
    }

    public void downloadTilesForPage(String viewerUrl, String zielVerzeichnis, int seitenIndex) {
        try {
            System.out.printf("🌐 Lade Viewer-Seite: %s%n", viewerUrl);
            driver.get(viewerUrl);
            wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector(".zoom-holder")));

            // Zoom maximieren
            for (int z = 0; z < 20; z++) {
                try {
                    WebElement zoomState = driver.findElement(By.cssSelector("a.zoom-state .current"));
                    String style = zoomState.getAttribute("style");
                    if (style != null && style.contains("left: 120px")) break;
                    WebElement zoomInButton = driver.findElement(By.cssSelector("a.zoom-in"));
                    if (zoomInButton.isDisplayed() && zoomInButton.isEnabled()) {
                        zoomInButton.click();
                        Thread.sleep(400);
                    } else break;
                } catch (Exception e) {
                    System.err.println("⚠️ Fehler beim Zoom: " + e.getMessage());
                }
            }

            WebElement zoomHolder = driver.findElement(By.cssSelector(".zoom-holder"));
            File tileFolder = new File(zielVerzeichnis, String.format("seite-%03d-tiles", seitenIndex));
            if (!tileFolder.exists()) Files.createDirectories(tileFolder.toPath());

            int scrollWidth = 8192;
            int scrollHeight = 8192;
            try {
                scrollWidth = ((Long) js.executeScript("return arguments[0].scrollWidth;", zoomHolder)).intValue();
                scrollHeight = ((Long) js.executeScript("return arguments[0].scrollHeight;", zoomHolder)).intValue();
                System.out.printf("📐 Scrollbereich erkannt: %d x %d px%n", scrollWidth, scrollHeight);
            } catch (Exception e) {
                System.err.println("⚠️ Fehler beim Auslesen der Scrollgröße: " + e.getMessage());
            }

            Set<String> seenSrcs = new HashSet<>();
            int step = 256;
            int tilesSaved = 0;
            int tilesSkipped = 0;
            int errors = 0;
            long startTime = System.currentTimeMillis();

            for (int y = 0; y <= scrollHeight; y += step) {
                for (int x = 0; x <= scrollWidth; x += step) {
                    try {
                        System.out.printf("🔄 Scrolle zu Position x=%d, y=%d...%n", x, y);
                        js.executeScript("arguments[0].scrollTo(arguments[1], arguments[2]);", zoomHolder, x, y);
                        actions.moveToElement(zoomHolder, x % 200 + 20, y % 200 + 20).perform();
                        Thread.sleep(800);
                    } catch (Exception e) {
                        System.err.printf("⚠️ Fehler beim Scrollen zu (%d,%d): %s%n", x, y, e.getMessage());
                        errors++;
                        continue;
                    }

                    List<WebElement> tiles;
                    try {
                        tiles = driver.findElements(By.cssSelector(".zoom-tiles img"));
                    } catch (Exception e) {
                        System.err.println("⚠️ Fehler beim Finden der Tiles: " + e.getMessage());
                        errors++;
                        continue;
                    }

                    System.out.printf("🔍 %d Tiles gefunden an Position (%d,%d)%n", tiles.size(), x, y);

                    for (WebElement img : tiles) {
                        try {
                            String src = img.getAttribute("_src");
                            if (src == null) {
                                tilesSkipped++;
                                continue;
                            }
                            if (src.startsWith("/")) {
                                src = "https://www.archion.de" + src;
                            }
                            if (seenSrcs.contains(src)) {
                                tilesSkipped++;
                                continue;
                            }

                            String style = img.getAttribute("style");
                            int left = extractPixel(style, "left");
                            int top = extractPixel(style, "top");
                            String filename = String.format("tile_%d_%d.png", left, top);
                            File tileFile = new File(tileFolder, filename);

                            try (InputStream in = new URL(src).openStream()) {
                                BufferedImage tile = ImageIO.read(in);
                                if (tile != null) {
                                    ImageIO.write(tile, "png", tileFile);
                                    tilesSaved++;
                                    System.out.printf("💾 Gespeichert: %s%n", filename);
                                }
                            } catch (Exception e) {
                                System.err.printf("❌ Fehler beim Laden oder Schreiben von: %s%n", src);
                                errors++;
                            }

                            seenSrcs.add(src);
                        } catch (Exception e) {
                            System.err.println("⚠️ Fehler beim Verarbeiten eines Tiles: " + e.getMessage());
                            errors++;
                        }
                    }

                    long elapsed = (System.currentTimeMillis() - startTime) / 1000;
                    System.out.printf("📊 Gesamt: %d gespeichert, %d übersprungen, %d Fehler, %ds seit Start%n%n",
                            tilesSaved, tilesSkipped, errors, elapsed);
                }
            }

            System.out.printf("✅ Alle Tiles für Seite %d gespeichert (%d Tiles) in %s%n",
                    seitenIndex, tilesSaved, tileFolder.getAbsolutePath());

        } catch (Exception e) {
            System.err.println("❌ Schwerer Fehler: " + e.getMessage());
            e.printStackTrace();
        }
    }
}
