from __future__ import annotations

from quart import Blueprint, make_response, request, g, abort
from sqlalchemy import select, or_
from sqlalchemy.orm import selectinload

from shared.browser.app.authz import require_login
from shared.browser.app.utils.htmx import is_htmx_request
from shared.sx.helpers import sx_response
from models import Snippet


VALID_VISIBILITY = frozenset({"private", "shared", "admin"})


async def _visible_snippets(session):
    """Return snippets visible to the current user (own + shared + admin-if-admin)."""
    uid = g.user.id
    is_admin = g.rights.get("admin")

    filters = [Snippet.user_id == uid, Snippet.visibility == "shared"]
    if is_admin:
        filters.append(Snippet.visibility == "admin")

    rows = (await session.execute(
        select(Snippet).where(or_(*filters)).order_by(Snippet.name)
    )).scalars().all()

    return rows


def register():
    bp = Blueprint("snippets", __name__, url_prefix="/settings/snippets")

    @bp.before_request
    async def _prepare_page_data():
        if "defpage_" not in (request.endpoint or ""):
            return
        snippets = await _visible_snippets(g.s)
        is_admin = g.rights.get("admin")
        from shared.sx.page import get_template_context
        from sx.sx_components import _snippets_main_panel_sx
        tctx = await get_template_context()
        tctx["snippets"] = snippets
        tctx["is_admin"] = is_admin
        g.snippets_content = _snippets_main_panel_sx(tctx)

    from shared.sx.pages import mount_pages
    mount_pages(bp, "blog", names=["snippets-page"])

    @bp.delete("/<int:snippet_id>/")
    @require_login
    async def delete_snippet(snippet_id: int):
        """Delete a snippet. Owners delete their own; admins can delete any."""
        snippet = await g.s.get(Snippet, snippet_id)
        if not snippet:
            abort(404)

        is_admin = g.rights.get("admin")
        if snippet.user_id != g.user.id and not is_admin:
            abort(403)

        await g.s.delete(snippet)
        await g.s.flush()

        snippets = await _visible_snippets(g.s)
        from sx.sx_components import render_snippets_list
        return sx_response(render_snippets_list(snippets, is_admin))

    @bp.patch("/<int:snippet_id>/visibility/")
    @require_login
    async def patch_visibility(snippet_id: int):
        """Change snippet visibility. Admin only."""
        if not g.rights.get("admin"):
            abort(403)

        snippet = await g.s.get(Snippet, snippet_id)
        if not snippet:
            abort(404)

        form = await request.form
        visibility = form.get("visibility", "").strip()

        if visibility not in VALID_VISIBILITY:
            abort(400)

        snippet.visibility = visibility
        await g.s.flush()

        snippets = await _visible_snippets(g.s)
        from sx.sx_components import render_snippets_list
        return sx_response(render_snippets_list(snippets, True))

    return bp
