from __future__ import annotations

import json
from pathlib import Path

from flask import Flask
from markupsafe import escape
try:
    import pyphen
except ModuleNotFoundError:  # pragma: no cover - optional dependency in local dev
    pyphen = None

from config import Config

from .cli import register_cli, seed_badges
from .extensions import csrf, db, login_manager
from .forms import QuickTaskForm
from .models import QuickWin
from .routes import auth, main, scoreboard, settings, tasks
from .routes.main import load_icon_svg
from .services.app_settings import get_quick_task_config
from .services.badges import sync_existing_badges
from .services.bootstrap import ensure_schema_and_admins
from .services.dates import MONTH_NAMES, local_now
from .services.monthly import archive_months_missing_up_to_previous

DE_HYPHENATOR = pyphen.Pyphen(lang="de_DE") if pyphen else None


def _fallback_soft_hyphenate(word: str) -> str:
    return word


def create_app(config_class: type[Config] = Config) -> Flask:
    app = Flask(__name__, static_folder="static", template_folder="templates")
    app.config.from_object(config_class)

    manifest_path = Path(app.root_path).parent / "CloudronManifest.json"
    try:
        app.config["APP_VERSION"] = json.loads(manifest_path.read_text(encoding="utf-8")).get("version", "0.0.0")
    except FileNotFoundError:
        app.config["APP_VERSION"] = "0.0.0"

    app.config["DATA_DIR"].mkdir(parents=True, exist_ok=True)
    app.config["UPLOAD_FOLDER"].mkdir(parents=True, exist_ok=True)

    db.init_app(app)
    login_manager.init_app(app)
    csrf.init_app(app)

    with app.app_context():
        db.create_all()
        ensure_schema_and_admins()
        seed_badges()
        sync_existing_badges()

    register_cli(app)

    app.register_blueprint(main.bp)
    app.register_blueprint(auth.bp)
    app.register_blueprint(tasks.bp)
    app.register_blueprint(scoreboard.bp)
    app.register_blueprint(settings.bp)

    app.jinja_env.globals["icon_svg"] = lambda name: load_icon_svg(name, app.static_folder)

    @app.before_request
    def ensure_archives():
        archive_months_missing_up_to_previous()

    @app.context_processor
    def inject_globals():
        quick_task_form = QuickTaskForm(prefix="quick")
        quick_task_config = get_quick_task_config()
        quick_task_form.effort.choices = [
            (key, values["label"])
            for key, values in quick_task_config.items()
        ]
        quick_wins = QuickWin.query.filter_by(active=True).order_by(QuickWin.sort_order.asc(), QuickWin.id.asc()).all()
        def asset_version(filename: str) -> int:
            path = Path(app.static_folder) / filename
            try:
                return int(path.stat().st_mtime)
            except FileNotFoundError:
                return 1

        return {
            "app_name": app.config["APP_NAME"],
            "app_version": app.config["APP_VERSION"],
            "nav_items": [
                ("tasks.my_tasks", "Meine Aufgaben", "house"),
                ("tasks.all_tasks", "Alle", "list"),
                ("tasks.create", "Neu", "plus"),
                ("tasks.calendar_view", "Kalender", "calendar"),
                ("scoreboard.index", "Highscore", "trophy"),
                ("settings.index", "Optionen", "gear"),
            ],
            "mobile_nav_items": [
                ("tasks.my_tasks", "Meine Aufgaben", "house"),
                ("tasks.all_tasks", "Alle Aufgaben", "list"),
                ("tasks.calendar_view", "Kalender", "calendar"),
                ("scoreboard.index", "Highscore", "trophy"),
                ("settings.index", "Optionen", "gear"),
            ],
            "icon_svg": lambda name: load_icon_svg(name, app.static_folder),
            "asset_version": asset_version,
            "now_local": local_now(),
            "quick_task_form": quick_task_form,
            "quick_task_config": quick_task_config,
            "quick_wins": quick_wins,
        }

    @app.template_filter("date_de")
    def date_de(value):
        return value.strftime("%d.%m.%Y") if value else "—"

    @app.template_filter("datetime_de")
    def datetime_de(value):
        return value.strftime("%d.%m.%Y, %H:%M") if value else "—"

    @app.template_filter("month_name")
    def month_name(value):
        return MONTH_NAMES[value]

    @app.template_filter("hyphenate_de")
    def hyphenate_de(value):
        if not value:
            return ""

        text = str(value)
        parts: list[str] = []
        current = []

        def flush_word():
            if not current:
                return
            word = "".join(current)
            if len(word) >= 6:
                if DE_HYPHENATOR:
                    parts.append(DE_HYPHENATOR.inserted(word, "\u00AD"))
                else:
                    parts.append(_fallback_soft_hyphenate(word))
            else:
                parts.append(word)
            current.clear()

        for char in text:
            if char.isalpha() or char in "ÄÖÜäöüß":
                current.append(char)
            else:
                flush_word()
                parts.append(char)

        flush_word()
        return escape("".join(parts))

    return app
