from flask import Flask, Blueprint, send_from_directory, redirect, render_template, session, request, jsonify
import os
import csv
import shutil
import sys
import importlib
import pkgutil
import json
from pathlib import Path
from datetime import datetime

from routes.passkey_routes import passkey_bp
from routes.taschengeld_routes import taschengeld_bp


# =====================================================
# 🔥 CSV MERGE LOGIK (UNVERÄNDERT)
# =====================================================

def merge_fahrtenbuch():
    base_dir = os.path.dirname(os.path.abspath(__file__))
    data_dir = os.path.join(base_dir, "static/fahrtkosten/data")
    archiv_dir = os.path.join(data_dir, "Archiv")

    os.makedirs(archiv_dir, exist_ok=True)

    main_file = os.path.join(data_dir, "Fahrtenbuch.csv")

    files = [
        f for f in os.listdir(data_dir)
        if f.startswith("Fahrtenbuch_") and f.endswith(".csv")
    ]

    if not files:
        return

    existing_rows = set()
    header = None
    merged_rows = []

    if os.path.exists(main_file):
        with open(main_file, newline="", encoding="utf-8") as f:
            reader = csv.reader(f, delimiter=";")
            rows = list(reader)

            if rows:
                header = rows[0]

                for row in rows[1:]:
                    key = "|".join(row)
                    existing_rows.add(key)
                    merged_rows.append(row)

    for filename in files:
        path = os.path.join(data_dir, filename)

        with open(path, newline="", encoding="utf-8") as f:
            reader = csv.reader(f, delimiter=";")
            rows = list(reader)

            if not rows:
                continue

            file_header = rows[0]

            if header is None:
                header = file_header

            for row in rows[1:]:
                key = "|".join(row)

                if key not in existing_rows:
                    existing_rows.add(key)
                    merged_rows.append(row)

        shutil.move(path, os.path.join(archiv_dir, filename))

    if header:
        with open(main_file, "w", newline="", encoding="utf-8") as f:
            writer = csv.writer(f, delimiter=";")
            writer.writerow(header)
            writer.writerows(merged_rows)


# =====================================================
# BASIS PFAD SETUP
# =====================================================

BASE_DIR = Path(__file__).resolve().parent
os.chdir(BASE_DIR)

BASE = os.path.dirname(__file__)
LOGIC = os.path.join(BASE, "logic")

for p in (BASE, LOGIC):
    if p not in sys.path:
        sys.path.insert(0, p)


# =====================================================
# APP ERSTELLEN
# =====================================================

def create_or_get_app():

    for modname in ("main", "server", "application"):
        try:
            m = importlib.import_module(modname)

            if hasattr(m, "create_app") and callable(m.create_app):
                a = m.create_app()
                if a:
                    a.secret_key = "super-secret-key-change-this"
                    return a

            if hasattr(m, "app"):
                a = getattr(m, "app")
                if a:
                    a.secret_key = "super-secret-key-change-this"
                    return a

        except Exception:
            continue

    app = Flask(
        __name__,
        template_folder="templates",
        static_folder="static"
    )

    app.secret_key = "super-secret-key-change-this"

    return app


app = create_or_get_app()


# =====================================================
# DATENBANK INITIALISIERUNG
# =====================================================

try:
    from database import init_db, get_db_connection
    init_db()
except Exception as e:
    print("DB INIT ERROR:", e)
    raise


# =====================================================
# BLUEPRINTS AUTO-REGISTRIERUNG
# =====================================================

def _process_module(mod, fqname, log):

    registered = False

    for name, obj in vars(mod).items():

        if isinstance(obj, Blueprint):
            app.register_blueprint(obj)
            log.append(f"[OK] blueprint {fqname}.{name}")
            registered = True

    for fn_name in ("init_app", "register", "setup"):

        fn = getattr(mod, fn_name, None)

        if callable(fn):

            try:
                fn(app)
                log.append(f"[OK] {fqname}.{fn_name}(app)")
                registered = True

            except Exception as e:
                log.append(f"[ERR] call {fqname}.{fn_name}: {e}")

    if not registered:
        log.append(f"[SKIP] {fqname}")


def _process_package(pkgname, log):

    try:
        mod = importlib.import_module(pkgname)

    except Exception as e:
        log.append(f"[ERR] import {pkgname}: {e}")
        return False

    if getattr(mod, "__path__", None):

        for _, mn, _ in pkgutil.walk_packages(mod.__path__, mod.__name__ + "."):
            try:
                sub = importlib.import_module(mn)
                _process_module(sub, mn, log)
            except Exception as e:
                log.append(f"[ERR] import {mn}: {e}")

    _process_module(mod, pkgname, log)
    return True


def register_everything():

    log = []

    for name in ("routes", "blueprints", "modules"):
        _process_package(name, log)

    try:
        with open("/tmp/routes_autoreg.log", "w", encoding="utf-8") as f:
            f.write("\n".join(log))
    except Exception:
        pass


register_everything()

# Fallback: Taschengeld-Blueprint explizit registrieren,
# falls es aus irgendeinem Grund nicht im url_map landet
if "taschengeld_bp" not in app.blueprints:
    app.register_blueprint(taschengeld_bp)

print("🔥 Pflegebudget Routen aktiv")


# =====================================================
# LOGIN SCHUTZ
# =====================================================

@app.before_request
def global_login_protection():

    path = request.path

    if path.startswith("/static"):
        return

    if path.startswith("/api/passkey"):
        return

    if path.startswith("/_"):
        return

    if path == "/":
        return

    if not session.get("user"):
        return redirect("/")


# =====================================================
# ROUTEN
# =====================================================

@app.get("/")
def index():

    if session.get("user"):
        return redirect("/app")

    return render_template("passkey_test.html")


@app.route("/app")
def app_home():
    if not session.get("user"):
        return redirect("/")
    return send_from_directory("static/app", "index.html")


@app.route("/modul/fahrtkosten")
def modul_fahrtkosten():
    merge_fahrtenbuch()

    base_dir = os.path.dirname(os.path.abspath(__file__))
    return send_from_directory(
        os.path.join(base_dir, "static/fahrtkosten"),
        "index.html"
    )


@app.route("/modul/biografie")
def modul_biografie():
    base_dir = os.path.dirname(os.path.abspath(__file__))
    return send_from_directory(
        os.path.join(base_dir, "static/biografie"),
        "index.html"
    )


@app.route("/modul/pflegebudget-manager")
def modul_pflegebudget_manager():
    base_dir = os.path.dirname(os.path.abspath(__file__))
    return send_from_directory(
        os.path.join(base_dir, "static/pflegebudget_manager"),
        "index.html"
    )
@app.route("/logout")
def logout():
    session.clear()
    return redirect("/")


# =====================================================
# 🔥 PFLEGEBUDGET: BERECHNEN
# =====================================================

@app.route("/modul/pflegebudget-manager/berechnen", methods=["POST"])
def pflegebudget_berechnen():
    from logic.pflegebudget_manager import berechne_budget

    data = request.get_json(force=True) or {}
    result = berechne_budget(data)
    return jsonify(result)


# =====================================================
# 🔥 PFLEGEBUDGET: SPEICHERN
# =====================================================

@app.route("/modul/pflegebudget-manager/speichern", methods=["POST"])
def speichern_kunde():

    data = request.get_json(force=True) or {}

    kundennummer = (data.get("kundennummer") or "").strip()
    name = (data.get("name") or "").strip()

    if not kundennummer or not name:
        return jsonify({"error": "Kundennummer und Name erforderlich"}), 400

    conn = get_db_connection()
    cur = conn.cursor()

    now = datetime.now().isoformat()

    cur.execute("SELECT id FROM kunden WHERE kundennummer = ?", (kundennummer,))
    row = cur.fetchone()

    if row:
        kunden_id = row["id"]
        cur.execute("""
            UPDATE kunden
            SET name = ?, updated_at = ?
            WHERE id = ?
        """, (name, now, kunden_id))
    else:
        cur.execute("""
            INSERT INTO kunden (kundennummer, name, created_at, updated_at)
            VALUES (?, ?, ?, ?)
        """, (kundennummer, name, now, now))
        kunden_id = cur.lastrowid

    heute = datetime.today()
    jahr = heute.year
    monat = heute.month

    cur.execute("""
        INSERT OR REPLACE INTO budget_monatsstaende (
            kunden_id, jahr, monat,
            pflegegrad, stundensatz, fahrtpauschale,
            uebertrag_entlastung,
            verbrauch_entlastung_bisher_jahr,
            verbrauch_entlastung_monat,
            verbrauch_sachleistung_monat,
            verbrauch_verhinderung_monat,
            verbrauch_verhinderung_bisher_jahr,
            form_data_json,
            created_at, updated_at
        )
        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    """, (
        kunden_id,
        jahr,
        monat,
        data.get("pflegegrad", 2),
        data.get("stundensatz", 0),
        data.get("fahrtpauschale", 0),
        data.get("uebertrag_entlastung", 0),
        data.get("verbrauch_entlastung", 0),
        data.get("verbrauch_entlastung_monat", 0),
        data.get("verbrauch_sachleistung_monat", 0),
        data.get("verbrauch_verhinderung_monat", 0),
        data.get("verbrauch_verhinderung", 0),
        json.dumps(data, ensure_ascii=False),
        now,
        now
    ))

    cur.execute("""
        DELETE FROM budget_einsaetze
        WHERE kunden_id = ? AND jahr = ? AND monat = ?
    """, (kunden_id, jahr, monat))

    for e in data.get("einsaetze", []):
        cur.execute("""
            INSERT INTO budget_einsaetze (
                kunden_id, jahr, monat,
                leistung, anbieter, topf, betrag,
                created_at, updated_at
            )
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
        """, (
            kunden_id,
            jahr,
            monat,
            e.get("leistung"),
            e.get("anbieter"),
            e.get("topf"),
            e.get("betrag", 0),
            now,
            now
        ))

    conn.commit()
    conn.close()

    return jsonify({"status": "ok"})


# =====================================================
# 🔥 PFLEGEBUDGET: LADEN
# =====================================================

@app.route("/modul/pflegebudget-manager/laden", methods=["POST"])
def laden_kunde():

    data = request.get_json(force=True) or {}
    kundennummer = (data.get("kundennummer") or "").strip()

    if not kundennummer:
        return jsonify({"error": "kundennummer fehlt"}), 400

    conn = get_db_connection()
    cur = conn.cursor()

    cur.execute("SELECT id FROM kunden WHERE kundennummer = ?", (kundennummer,))
    row = cur.fetchone()

    if not row:
        conn.close()
        return jsonify({"error": "nicht gefunden"}), 404

    kunden_id = row["id"]

    heute = datetime.today()
    jahr = heute.year
    monat = heute.month

    cur.execute("""
        SELECT form_data_json FROM budget_monatsstaende
        WHERE kunden_id = ? AND jahr = ? AND monat = ?
    """, (kunden_id, jahr, monat))

    row = cur.fetchone()

    if not row:
        conn.close()
        return jsonify({"error": "kein Datensatz"}), 404

    form_data = json.loads(row["form_data_json"])

    cur.execute("""
        SELECT leistung, anbieter, topf, betrag
        FROM budget_einsaetze
        WHERE kunden_id = ? AND jahr = ? AND monat = ?
        ORDER BY id ASC
    """, (kunden_id, jahr, monat))

    einsaetze = [dict(r) for r in cur.fetchall()]

    conn.close()

    form_data["einsaetze"] = einsaetze

    return jsonify(form_data)


@app.route("/setup")
def setup():
    return render_template("passkey_setup.html")


# =====================================================
# DEBUG / HEALTH
# =====================================================

@app.get("/_debug/routes")
def __routes():
    s = "\n".join(sorted(str(r) for r in app.url_map.iter_rules()))
    return (s, 200, {"Content-Type": "text/plain; charset=utf-8"})


@app.get("/_debug/blueprints_log")
def __bp_log():
    try:
        with open("/tmp/routes_autoreg.log", "r", encoding="utf-8") as f:
            c = f.read()
    except Exception:
        c = "(kein Log)"
    return (c, 200, {"Content-Type": "text/plain; charset=utf-8"})


@app.get("/_health")
def __health_ok():
    return "OK", 200


# =====================================================
# NO CACHE
# =====================================================

@app.after_request
def no_cache(response):
    response.headers["Cache-Control"] = "no-store"
    return response


print("🔥 App gestartet – prüfe Routen unter /_debug/routes")