package de.roko.genalogy.downloader.database;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.File;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

public class DokumentExtractor {

    private static final String DB = "/Users/robertkoch/dev/arch/archion.db";

    public void run() throws Exception {
        try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + DB)) {
            String sql = "SELECT id, name, link FROM ort ORDER BY id";
            try (PreparedStatement stmt = conn.prepareStatement(sql);
                 ResultSet rs = stmt.executeQuery()) {

                while (rs.next()) {
                    int ortId = rs.getInt("id");
                    String ortName = rs.getString("name");
                    String ortLink = rs.getString("link");

                    System.out.println("\n📘 Lese Bücher für Ort: " + ortName);
                    List<Buch> buecher = extractBuecher(ortId, ortLink);
                    saveBuecher(buecher, conn);
                    System.out.println("→ " + buecher.size() + " Bücher gespeichert.");
                }
            }
        }
    }

    public void run(int id) throws Exception {
        try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + DB)) {
            System.out.println("📂 Aktive DB-Datei: " + new java.io.File(DB).getAbsolutePath());

            try (Statement stmt = conn.createStatement()) {
                ResultSet rs = stmt.executeQuery("PRAGMA table_info(buch)");
                System.out.println("📋 Spalten in 'buch':");
                while (rs.next()) {
                    System.out.println(" - " + rs.getString("name"));
                }

                rs = stmt.executeQuery("PRAGMA index_list('buch')");
                System.out.println("📊 Indizes auf 'buch':");
                while (rs.next()) {
                    System.out.println(" - " + rs.getString("name") + ", unique: " + rs.getBoolean("unique"));
                }
            }

            String sql = "SELECT id, name, link FROM ort WHERE id = " + id;
            try (PreparedStatement stmt = conn.prepareStatement(sql);
                 ResultSet rs = stmt.executeQuery()) {

                while (rs.next()) {
                    int ortId = rs.getInt("id");
                    String ortName = rs.getString("name");
                    String ortLink = rs.getString("link");

                    System.out.println("\n📘 Lese Bücher für Ort: " + ortName);
                    System.out.println("Link: " + ortLink);
                    List<Buch> buecher = extractBuecher(ortId, ortLink);
                    saveBuecher(buecher, conn);
                    System.out.println("→ " + buecher.size() + " Bücher gespeichert.");
                }
            }
        }
    }

    private List<Buch> extractBuecher(int ortId, String ortLink) {
        List<Buch> list = new ArrayList<>();
        try {
            Document doc = Jsoup.connect(ortLink).get();
            Elements buchEintraege = doc.select("#archive-nav li.item");

            for (Element li : buchEintraege) {
                Element a = li.selectFirst("a");
                if (a == null) continue;


                Element span = a.selectFirst("span");
                if (span == null) { // 🔧 NEU: Schutz gegen fehlendes <span>
                    System.err.println("⚠️ Kein <span> in: " + a);
                    continue;
                }

                String titel = span.text().trim();
                String link = a.absUrl("href").trim();

                String typ = null;
                Element img = a.selectFirst("img");

                if (img != null) {
                    String src = img.attr("src");
                    int lastSlash = src.lastIndexOf('/');
                    int dot = src.lastIndexOf('.');
                    if (lastSlash != -1 && dot != -1 && dot > lastSlash) {
                        typ = src.substring(lastSlash + 1, dot);
                    }
                }

                Buch buch = extractBuchDetails(ortId, titel, link, typ);
                list.add(buch);
            }

        } catch (Exception e) {
            System.err.println("⚠️ Fehler beim Ort-Link " + ortLink + ": " + e.getMessage());
        }
        return list;
    }

    private Buch extractBuchDetails(int ortId, String titel, String link, String typ) {
        String zeitraum = null, enthaelt = null, anmerkung = null, signatur = null, archivname = null, viewerLink = null;

        try {
            Document detailDoc = Jsoup.connect(link).get();

            Element viewerEl = detailDoc.selectFirst("#steckbrief a[href*=\"/viewer/\"]");
            if (viewerEl != null) {
                viewerLink = viewerEl.absUrl("href");
            }

            Elements dl = detailDoc.select("#steckbrief dl");
            for (Element dt : dl.select("dt")) {
                String label = dt.text().trim().toLowerCase();
                Element dd = dt.nextElementSibling();
                if (dd == null) continue;
                String value = dd.text().trim();

                switch (label) {
                    case "zeitraum" -> zeitraum = value;
                    case "enthält auch" -> enthaelt = value;
                    case "anmerkung" -> anmerkung = value;
                    case "signatur lokal" -> signatur = value;
                    case "archiv" -> archivname = value;
                }
            }

        } catch (Exception e) {
            System.err.println("⚠️ Fehler beim Detail-Link " + link + ": " + e.getMessage());
        }

        return new Buch(ortId, titel, link, typ, zeitraum, enthaelt, anmerkung, signatur, archivname, viewerLink);
    }

    private void saveBuecher(List<Buch> list, Connection conn) throws SQLException {

        if (list.isEmpty()) return;

        List<String> vorhandeneTitel = getGespeicherteTitel(list.get(0).ortId(), conn); // 🔧 NEU
        List<Buch> neu = list.stream()
                .filter(b -> !vorhandeneTitel.contains(b.titel())) // 🔧 NEU: Duplikate überspringen
                .toList();

        System.out.println("🧮 " + (list.size() - neu.size()) + " Bücher existieren bereits und werden übersprungen."); // 🔧 NEU
        System.out.println("✅ " + neu.size() + " neue Bücher werden gespeichert."); // 🔧 NEU

        if (neu.isEmpty()) return;


        String sql = """
        INSERT INTO buch (
            ort_id, titel, typ, zeitraum, enthaelt,
            anmerkung, signatur, archivname, link, viewer_link
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
        ON CONFLICT(ort_id, titel)
        DO UPDATE SET
            typ = excluded.typ,
            zeitraum = excluded.zeitraum,
            enthaelt = excluded.enthaelt,
            anmerkung = excluded.anmerkung,
            signatur = excluded.signatur,
            archivname = excluded.archivname,
            link = excluded.link,
            viewer_link = excluded.viewer_link;
        """;

        try (PreparedStatement stmt = conn.prepareStatement(sql)) {
            for (Buch b : list) {
                stmt.setInt(1, b.ortId());
                stmt.setString(2, b.titel());
                stmt.setString(3, b.typ());
                stmt.setString(4, b.zeitraum());
                stmt.setString(5, b.enthaelt());
                stmt.setString(6, b.anmerkung());
                stmt.setString(7, b.signatur());
                stmt.setString(8, b.archivname());
                stmt.setString(9, b.link());
                stmt.setString(10, b.viewerLink());
                stmt.addBatch();
            }
            stmt.executeBatch();
        }
    }

    private List<String> getGespeicherteTitel(int ortId, Connection conn) throws SQLException {
        List<String> vorhandeneTitel = new ArrayList<>();
        String sql = "SELECT titel FROM buch WHERE ort_id = ?";
        try (PreparedStatement stmt = conn.prepareStatement(sql)) {
            stmt.setInt(1, ortId);
            try (ResultSet rs = stmt.executeQuery()) {
                while (rs.next()) {
                    vorhandeneTitel.add(rs.getString("titel"));
                }
            }
        }
        return vorhandeneTitel;
    }

    public void runForArchiv(String archivName) throws Exception {
        try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + DB)) {
            String sql = """
            SELECT ort.id, ort.name, ort.link
            FROM ort
            JOIN kreis ON ort.kreis_id = kreis.id
            JOIN archive ON kreis.archiv_id = archive.id
            WHERE archive.name = ?
            ORDER BY ort.id
        """;
            try (PreparedStatement stmt = conn.prepareStatement(sql)) {
                stmt.setString(1, archivName);
                runForOrtResultSet(stmt.executeQuery(), conn, archivName);
            }
        }
    }


    public void runForArchiv(int archivId) throws Exception {
        try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + DB)) {
            String sql = """
            SELECT ort.id, ort.name, ort.link
            FROM ort
            JOIN kreis ON ort.kreis_id = kreis.id
            WHERE kreis.archiv_id = ?
            ORDER BY ort.id
        """;
            try (PreparedStatement stmt = conn.prepareStatement(sql)) {
                stmt.setInt(1, archivId);
                runForOrtResultSet(stmt.executeQuery(), conn, "ID=" + archivId);
            }
        }
    }

    public void runForBundesland(String bundesland) throws Exception {
        try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + DB)) {
            String sql = """
            SELECT ort.id, ort.name, ort.link
            FROM ort
            JOIN kreis ON ort.kreis_id = kreis.id
            JOIN archive ON kreis.archiv_id = archive.id
            WHERE archive.bundesland = ?
            ORDER BY ort.id
        """;
            try (PreparedStatement stmt = conn.prepareStatement(sql)) {
                stmt.setString(1, bundesland);
                runForOrtResultSet(stmt.executeQuery(), conn, "Bundesland=" + bundesland);
            }
        }
    }


    // 🔧 Hilfsmethode zum Verarbeiten des ResultSets
    private void runForOrtResultSet(ResultSet rs, Connection conn, String label) throws Exception {
        int count = 0;
        while (rs.next()) {
            int ortId = rs.getInt("id");
            String ortName = rs.getString("name");
            String ortLink = rs.getString("link");

            System.out.println("\n📘 Lese Bücher für Ort: " + ortName);
            List<Buch> buecher = extractBuecher(ortId, ortLink);
            saveBuecher(buecher, conn);
            System.out.println("→ " + buecher.size() + " Bücher gespeichert.");
            count++;
        }

        if (count == 0) {
            System.out.println("⚠️ Keine Orte für Archiv '" + label + "' gefunden.");
        }
    }

    private File buildBildOrdnerPfad(
            String baseDir,
            String bundesland,
            String archivname,
            String kreisname,
            String ort,
            String buchTitel
    ) {
        // Hilfsfunktion für Dateisystem-sichere Namen
        Function<String, String> safe = s ->
                s == null ? "unbekannt" : s.replaceAll("[^\\wäöüÄÖÜß\\-\\s]", "").trim();

        List<String> pfad = new ArrayList<>();
        pfad.add(baseDir);
        pfad.add(safe.apply(bundesland));
        pfad.add(safe.apply(archivname));
        if (kreisname != null && !kreisname.isBlank()) {
            pfad.add(safe.apply(kreisname));
        }
        pfad.add(safe.apply(ort));
        pfad.add(safe.apply(buchTitel));

        File ordner = new File(String.join(File.separator, pfad));
        if (!ordner.exists()) {
            ordner.mkdirs();
        }
        return ordner;
    }

    public void erstelleBildOrdnerFuerAlleBuecher(String basisPfad) throws Exception {
        try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + DB)) {
            String sql = """
            SELECT 
                buch.id AS buch_id,
                buch.titel AS buch_titel,
                ort.name AS ort_name,
                kreis.name AS kreis_name,
                archive.name AS archiv_name,
                archive.bundesland AS bundesland
            FROM buch
            JOIN ort ON buch.ort_id = ort.id
            LEFT JOIN kreis ON ort.kreis_id = kreis.id
            JOIN archive ON ort.archiv_id = archive.id
            ORDER BY archive.bundesland, archive.name, kreis.name, ort.name, buch.titel
        """;

            try (PreparedStatement stmt = conn.prepareStatement(sql);
                 ResultSet rs = stmt.executeQuery()) {

                int count = 0;
                while (rs.next()) {
                    String buchTitel = rs.getString("buch_titel");
                    String ort = rs.getString("ort_name");
                    String kreis = rs.getString("kreis_name");
                    String archiv = rs.getString("archiv_name");
                    String bundesland = rs.getString("bundesland");

                    File ordner = buildBildOrdnerPfad(basisPfad, bundesland, archiv, kreis, ort, buchTitel);
                    System.out.println("📁 Ordner: " + ordner.getAbsolutePath());
                    count++;
                }

                System.out.println("✅ " + count + " Bildordner vorbereitet.");
            }
        }
    }


    public record Buch(
            int ortId,
            String titel,
            String typ,
            String zeitraum,
            String enthaelt,
            String anmerkung,
            String signatur,
            String archivname,
            String link,
            String viewerLink
    ) {}
}
