"""Public web routes for the SmartTools UI."""

from __future__ import annotations

from types import SimpleNamespace
from typing import Any, Dict, List, Optional, Tuple

from markupsafe import Markup, escape
from flask import current_app, redirect, render_template, request, session, url_for

from smarttools.registry.db import connect_db, query_all, query_one

from . import web_bp


def _api_get(path: str, params: Optional[Dict[str, Any]] = None, token: Optional[str] = None) -> Tuple[int, Dict[str, Any]]:
    client = current_app.test_client()
    headers = {}
    if token:
        headers["Authorization"] = f"Bearer {token}"
    response = client.get(path, query_string=params or {}, headers=headers)
    return response.status_code, response.get_json(silent=True) or {}


def _title_case(value: str) -> str:
    return value.replace("-", " ").title()


def _build_pagination(meta: Dict[str, Any]) -> SimpleNamespace:
    page = int(meta.get("page", 1))
    total_pages = int(meta.get("total_pages", 1))
    return SimpleNamespace(
        page=page,
        pages=total_pages,
        has_prev=page > 1,
        has_next=page < total_pages,
        prev_num=page - 1,
        next_num=page + 1,
    )


def _render_readme(readme: Optional[str]) -> str:
    if not readme:
        return ""
    escaped = escape(readme)
    return Markup("<pre class=\"whitespace-pre-wrap\">") + escaped + Markup("</pre>")


def _load_categories() -> List[SimpleNamespace]:
    status, payload = _api_get("/api/v1/categories", params={"per_page": 100})
    if status != 200:
        return []
    categories = []
    for item in payload.get("data", []):
        name = item.get("name")
        if not name:
            continue
        categories.append(SimpleNamespace(
            name=name,
            display_name=_title_case(name),
            count=item.get("tool_count", 0),
            description=item.get("description"),
            icon=item.get("icon"),
        ))
    return categories


def _load_publisher(slug: str) -> Optional[Dict[str, Any]]:
    conn = connect_db()
    try:
        row = query_one(
            conn,
            "SELECT slug, display_name, bio, website, verified, created_at FROM publishers WHERE slug = ?",
            [slug],
        )
        return dict(row) if row else None
    finally:
        conn.close()


def _load_publisher_tools(slug: str) -> List[Dict[str, Any]]:
    conn = connect_db()
    try:
        rows = query_all(
            conn,
            """
            WITH latest AS (
                SELECT owner, name, MAX(id) AS max_id
                FROM tools
                WHERE owner = ? AND version NOT LIKE '%-%'
                GROUP BY owner, name
            )
            SELECT t.owner, t.name, t.version, t.description, t.category, t.downloads, t.published_at
            FROM tools t
            JOIN latest ON t.owner = latest.owner AND t.name = latest.name AND t.id = latest.max_id
            ORDER BY t.downloads DESC, t.published_at DESC
            """,
            [slug],
        )
        return [dict(row) for row in rows]
    finally:
        conn.close()


def _load_tool_versions(owner: str, name: str) -> List[Dict[str, Any]]:
    conn = connect_db()
    try:
        rows = query_all(
            conn,
            "SELECT version, published_at FROM tools WHERE owner = ? AND name = ? ORDER BY id DESC",
            [owner, name],
        )
        return [dict(row) for row in rows]
    finally:
        conn.close()


def _load_tool_id(owner: str, name: str, version: str) -> Optional[int]:
    conn = connect_db()
    try:
        row = query_one(
            conn,
            "SELECT id FROM tools WHERE owner = ? AND name = ? AND version = ?",
            [owner, name, version],
        )
        return int(row["id"]) if row else None
    finally:
        conn.close()


def _load_current_publisher() -> Optional[Dict[str, Any]]:
    slug = session.get("user", {}).get("slug")
    if not slug:
        return None
    conn = connect_db()
    try:
        row = query_one(
            conn,
            """
            SELECT id, slug, display_name, email, verified, bio, website, created_at
            FROM publishers
            WHERE slug = ?
            """,
            [slug],
        )
        return dict(row) if row else None
    finally:
        conn.close()


def _load_pending_prs(publisher_id: int) -> List[Dict[str, Any]]:
    conn = connect_db()
    try:
        rows = query_all(
            conn,
            """
            SELECT owner, name, version, pr_url, status, created_at
            FROM pending_prs
            WHERE publisher_id = ?
            ORDER BY created_at DESC
            """,
            [publisher_id],
        )
        return [dict(row) for row in rows]
    finally:
        conn.close()


def _require_login() -> Optional[Any]:
    if not session.get("auth_token"):
        next_url = request.path
        if request.query_string:
            next_url = f"{next_url}?{request.query_string.decode('utf-8')}"
        return redirect(url_for("web.login", next=next_url))
    return None


@web_bp.route("/", endpoint="home")
def home():
    status, payload = _api_get("/api/v1/stats/popular", params={"limit": 6})
    featured_tools = payload.get("data", []) if status == 200 else []
    show_ads = current_app.config.get("SHOW_ADS", False)
    return render_template(
        "pages/index.html",
        featured_tools=featured_tools,
        featured_contributor=None,
        show_ads=show_ads,
    )


def _home_alias():
    return home()


web_bp.add_url_rule("/", endpoint="index", view_func=_home_alias)


@web_bp.route("/tools", endpoint="tools")
def tools():
    return _render_tools()


def _render_tools(category_override: Optional[str] = None):
    page = request.args.get("page", 1)
    sort = request.args.get("sort", "downloads")
    category = category_override or request.args.get("category")
    query = request.args.get("q")
    params = {"page": page, "per_page": 12, "sort": sort}
    if category:
        params["category"] = category

    status, payload = _api_get("/api/v1/tools", params=params)
    if status != 200:
        return render_template("errors/500.html"), 500

    meta = payload.get("meta", {})
    categories = _load_categories()
    return render_template(
        "pages/tools.html",
        tools=payload.get("data", []),
        categories=categories,
        current_category=category,
        total_count=meta.get("total", 0),
        sort=sort,
        query=query,
        pagination=_build_pagination(meta),
    )


def _tools_alias():
    return tools()


web_bp.add_url_rule("/tools", endpoint="tools_browse", view_func=_tools_alias)


@web_bp.route("/category/<name>", endpoint="category")
def category(name: str):
    query = request.args.get("q")
    if query:
        return redirect(url_for("web.search", q=query, category=name))
    return _render_tools(category_override=name)


@web_bp.route("/search", endpoint="search")
def search():
    query = request.args.get("q", "").strip()
    page = request.args.get("page", 1)
    category = request.args.get("category")

    if query:
        params = {"q": query, "page": page, "per_page": 12}
        if category:
            params["category"] = category
        status, payload = _api_get("/api/v1/tools/search", params=params)
        if status != 200:
            return render_template("errors/500.html"), 500
        meta = payload.get("meta", {})
        return render_template(
            "pages/search.html",
            query=query,
            results=payload.get("data", []),
            pagination=_build_pagination(meta),
            popular_categories=[],
        )

    categories = sorted(_load_categories(), key=lambda c: c.count, reverse=True)[:8]
    return render_template(
        "pages/search.html",
        query="",
        results=[],
        pagination=None,
        popular_categories=categories,
    )


@web_bp.route("/tools/<owner>/<name>", endpoint="tool_detail")
def tool_detail(owner: str, name: str):
    status, payload = _api_get(f"/api/v1/tools/{owner}/{name}")
    if status == 404:
        return render_template("errors/404.html"), 404
    if status != 200:
        return render_template("errors/500.html"), 500

    tool = payload.get("data", {})
    tool["tags"] = ", ".join(tool.get("tags", [])) if isinstance(tool.get("tags"), list) else tool.get("tags")
    tool["readme_html"] = _render_readme(tool.get("readme"))
    tool_id = _load_tool_id(owner, name, tool.get("version", ""))
    tool["id"] = tool_id

    publisher = _load_publisher(owner)
    versions = _load_tool_versions(owner, name)
    return render_template(
        "pages/tool_detail.html",
        tool=tool,
        publisher=publisher,
        versions=versions,
    )


@web_bp.route("/tools/<owner>/<name>/versions/<version>", endpoint="tool_version")
def tool_version(owner: str, name: str, version: str):
    status, payload = _api_get(f"/api/v1/tools/{owner}/{name}", params={"version": version})
    if status == 404:
        return render_template("errors/404.html"), 404
    if status != 200:
        return render_template("errors/500.html"), 500
    tool = payload.get("data", {})
    tool["tags"] = ", ".join(tool.get("tags", [])) if isinstance(tool.get("tags"), list) else tool.get("tags")
    tool["readme_html"] = _render_readme(tool.get("readme"))
    tool["id"] = _load_tool_id(owner, name, tool.get("version", version))

    publisher = _load_publisher(owner)
    versions = _load_tool_versions(owner, name)
    return render_template(
        "pages/tool_detail.html",
        tool=tool,
        publisher=publisher,
        versions=versions,
    )


@web_bp.route("/publishers/<slug>", endpoint="publisher")
def publisher(slug: str):
    publisher_row = _load_publisher(slug)
    if not publisher_row:
        return render_template("errors/404.html"), 404
    tools = _load_publisher_tools(slug)
    return render_template(
        "pages/publisher.html",
        publisher=publisher_row,
        tools=tools,
    )


def _publisher_alias(slug: str):
    return publisher(slug)


web_bp.add_url_rule("/publishers/<slug>", endpoint="publisher_profile", view_func=_publisher_alias)


def _render_dashboard_overview():
    redirect_response = _require_login()
    if redirect_response:
        return redirect_response
    token = session.get("auth_token")
    user = _load_current_publisher() or session.get("user", {})
    status, payload = _api_get("/api/v1/me/tools", token=token)
    tools = payload.get("data", []) if status == 200 else []
    token_status, token_payload = _api_get("/api/v1/tokens", token=token)
    tokens = token_payload.get("data", []) if token_status == 200 else []
    stats = {
        "tools_count": len(tools),
        "total_downloads": sum(tool.get("downloads", 0) for tool in tools),
        "tokens_count": len(tokens),
    }
    return render_template(
        "dashboard/index.html",
        user=user,
        tools=tools,
        stats=stats,
    )


@web_bp.route("/dashboard", endpoint="dashboard")
def dashboard():
    return _render_dashboard_overview()


@web_bp.route("/dashboard/tools", endpoint="dashboard_tools")
def dashboard_tools():
    redirect_response = _require_login()
    if redirect_response:
        return redirect_response
    token = session.get("auth_token")
    user = _load_current_publisher() or session.get("user", {})
    status, payload = _api_get("/api/v1/me/tools", token=token)
    tools = payload.get("data", []) if status == 200 else []
    token_status, token_payload = _api_get("/api/v1/tokens", token=token)
    tokens = token_payload.get("data", []) if token_status == 200 else []
    stats = {
        "tools_count": len(tools),
        "total_downloads": sum(tool.get("downloads", 0) for tool in tools),
        "tokens_count": len(tokens),
    }
    pending_prs = []
    if user and user.get("id"):
        pending_prs = _load_pending_prs(int(user["id"]))
    return render_template(
        "dashboard/tools.html",
        user=user,
        tools=tools,
        stats=stats,
        pending_prs=pending_prs,
    )


@web_bp.route("/dashboard/tokens", endpoint="dashboard_tokens")
def dashboard_tokens():
    redirect_response = _require_login()
    if redirect_response:
        return redirect_response
    token = session.get("auth_token")
    user = _load_current_publisher() or session.get("user", {})
    tools_status, tools_payload = _api_get("/api/v1/me/tools", token=token)
    tools = tools_payload.get("data", []) if tools_status == 200 else []
    token_status, token_payload = _api_get("/api/v1/tokens", token=token)
    tokens = token_payload.get("data", []) if token_status == 200 else []
    for item in tokens:
        token_id = str(item.get("id", ""))
        item["token_suffix"] = token_id[-6:] if token_id else ""
        item["revoked_at"] = item.get("revoked_at")
    stats = {
        "tools_count": len(tools),
        "total_downloads": sum(tool.get("downloads", 0) for tool in tools),
        "tokens_count": len(tokens),
    }
    return render_template(
        "dashboard/tokens.html",
        user=user,
        tools=tools,
        stats=stats,
        tokens=tokens,
    )


@web_bp.route("/dashboard/settings", endpoint="dashboard_settings")
def dashboard_settings():
    redirect_response = _require_login()
    if redirect_response:
        return redirect_response
    token = session.get("auth_token")
    user = _load_current_publisher() or session.get("user", {})
    tools_status, tools_payload = _api_get("/api/v1/me/tools", token=token)
    tools = tools_payload.get("data", []) if tools_status == 200 else []
    token_status, token_payload = _api_get("/api/v1/tokens", token=token)
    tokens = token_payload.get("data", []) if token_status == 200 else []
    stats = {
        "tools_count": len(tools),
        "total_downloads": sum(tool.get("downloads", 0) for tool in tools),
        "tokens_count": len(tokens),
    }
    return render_template(
        "dashboard/settings.html",
        user=user,
        tools=tools,
        stats=stats,
        tokens=tokens,
        errors=[],
        success_message=None,
    )


@web_bp.route("/docs", defaults={"path": ""}, endpoint="docs")
@web_bp.route("/docs/<path:path>", endpoint="docs")
def docs(path: str):
    toc = [
        SimpleNamespace(slug="getting-started", title="Getting Started", children=[
            SimpleNamespace(slug="installation", title="Installation"),
            SimpleNamespace(slug="first-tool", title="Your First Tool"),
        ]),
        SimpleNamespace(slug="publishing", title="Publishing", children=[]),
        SimpleNamespace(slug="providers", title="Providers", children=[]),
    ]
    current = path or "getting-started"
    page = SimpleNamespace(
        title=_title_case(current),
        description="SmartTools documentation",
        content_html=f"<p>Documentation for <strong>{escape(current)}</strong> is coming soon.</p>",
        headings=[],
        parent=None,
    )
    show_ads = current_app.config.get("SHOW_ADS", False)
    return render_template(
        "pages/docs.html",
        page=page,
        toc=toc,
        current_path=current,
        prev_page=None,
        next_page=None,
        show_ads=show_ads,
    )


@web_bp.route("/tutorials", endpoint="tutorials")
def tutorials():
    core_tutorials = []
    video_tutorials = []
    return render_template(
        "pages/tutorials.html",
        core_tutorials=core_tutorials,
        video_tutorials=video_tutorials,
    )


@web_bp.route("/tutorials/<path:path>", endpoint="tutorials_path")
def tutorials_path(path: str):
    return render_template(
        "pages/content.html",
        title=_title_case(path),
        body="Tutorial content for this topic is coming soon.",
    )


web_bp.add_url_rule("/tutorials/<path:path>", endpoint="tutorial", view_func=tutorials_path)


@web_bp.route("/community", endpoint="community")
def community():
    return render_template(
        "pages/content.html",
        title="Community",
        body="Community features will live here. For now, join the discussion and share ideas.",
    )


@web_bp.route("/about", endpoint="about")
def about():
    return render_template("pages/about.html")


@web_bp.route("/donate", endpoint="donate")
def donate():
    return render_template(
        "pages/content.html",
        title="Support SmartTools",
        body="Donations help fund infrastructure, development, and broader access to AI tools.",
    )


@web_bp.route("/privacy", endpoint="privacy")
def privacy():
    return render_template("pages/privacy.html")


@web_bp.route("/terms", endpoint="terms")
def terms():
    return render_template("pages/terms.html")


@web_bp.route("/forgot-password", endpoint="forgot_password")
def forgot_password():
    return render_template(
        "pages/content.html",
        title="Reset Password",
        body="Password resets are not available yet. Please contact support if needed.",
    )
