"""Repository for per-user curated marketplace subscriptions (Model B opt-in).

Backed by the historically-named ``user_plugin_optouts`` table. Pre-v28 a row
represented an opt-OUT against an admin-granted plugin; v28 inverts the
semantic — row PRESENCE now means the user is subscribed. The DDL rename was
intentionally skipped to avoid migration churn on running operator instances;
the v28 migration wipes the rows so the inverted reading starts clean.

Used by ``src/marketplace_filter.py:resolve_user_marketplace`` to compute the
served plugin set as ``(rbac_grants ∩ subscriptions) ∪ store_installs``.
"""

from __future__ import annotations

from typing import Any, Dict, List, Set, Tuple

import duckdb


class UserCuratedSubscriptionsRepository:
    def __init__(self, conn: duckdb.DuckDBPyConnection):
        self.conn = conn

    def subscribe(
        self, user_id: str, marketplace_id: str, plugin_name: str
    ) -> bool:
        """Idempotent. Returns True iff a new row was inserted."""
        before = self.conn.execute(
            "SELECT 1 FROM user_plugin_optouts "
            "WHERE user_id = ? AND marketplace_id = ? AND plugin_name = ?",
            [user_id, marketplace_id, plugin_name],
        ).fetchone()
        if before:
            return False
        self.conn.execute(
            "INSERT INTO user_plugin_optouts "
            "(user_id, marketplace_id, plugin_name) VALUES (?, ?, ?) "
            "ON CONFLICT (user_id, marketplace_id, plugin_name) DO NOTHING",
            [user_id, marketplace_id, plugin_name],
        )
        return True

    def unsubscribe(
        self, user_id: str, marketplace_id: str, plugin_name: str
    ) -> bool:
        """Returns True iff a row was deleted."""
        before = self.conn.execute(
            "SELECT 1 FROM user_plugin_optouts "
            "WHERE user_id = ? AND marketplace_id = ? AND plugin_name = ?",
            [user_id, marketplace_id, plugin_name],
        ).fetchone()
        if not before:
            return False
        self.conn.execute(
            "DELETE FROM user_plugin_optouts "
            "WHERE user_id = ? AND marketplace_id = ? AND plugin_name = ?",
            [user_id, marketplace_id, plugin_name],
        )
        return True

    def is_subscribed(
        self, user_id: str, marketplace_id: str, plugin_name: str
    ) -> bool:
        return bool(
            self.conn.execute(
                "SELECT 1 FROM user_plugin_optouts "
                "WHERE user_id = ? AND marketplace_id = ? AND plugin_name = ?",
                [user_id, marketplace_id, plugin_name],
            ).fetchone()
        )

    def subscribed_set(self, user_id: str) -> Set[Tuple[str, str]]:
        """Return the user's subscriptions as a ``{(marketplace_id, plugin_name)}``
        set — the shape ``resolve_user_marketplace`` filters against.
        """
        rows = self.conn.execute(
            "SELECT marketplace_id, plugin_name FROM user_plugin_optouts "
            "WHERE user_id = ?",
            [user_id],
        ).fetchall()
        return {(r[0], r[1]) for r in rows}

    def list_for_user(self, user_id: str) -> List[Dict[str, Any]]:
        """Return the user's subscriptions ordered newest-first."""
        rows = self.conn.execute(
            "SELECT marketplace_id, plugin_name, opted_out_at "
            "FROM user_plugin_optouts WHERE user_id = ? "
            "ORDER BY opted_out_at DESC",
            [user_id],
        ).fetchall()
        return [
            {
                "marketplace_id": r[0],
                "plugin_name": r[1],
                "subscribed_at": r[2],
            }
            for r in rows
        ]

    def delete_for_plugin(
        self, marketplace_id: str, plugin_name: str
    ) -> int:
        """Drop all users' subscriptions for a given plugin.

        Called when a plugin's RBAC grant is revoked or the parent marketplace
        is deleted. Returns count of rows deleted (audit telemetry).
        """
        before = self.conn.execute(
            "SELECT COUNT(*) FROM user_plugin_optouts "
            "WHERE marketplace_id = ? AND plugin_name = ?",
            [marketplace_id, plugin_name],
        ).fetchone()[0]
        self.conn.execute(
            "DELETE FROM user_plugin_optouts "
            "WHERE marketplace_id = ? AND plugin_name = ?",
            [marketplace_id, plugin_name],
        )
        return int(before)

    def delete_for_marketplace(self, marketplace_id: str) -> int:
        """Drop all subscriptions for every plugin in a marketplace.

        Called from ``DELETE /api/marketplaces/{id}`` cleanup path.
        Returns count of rows deleted.
        """
        before = self.conn.execute(
            "SELECT COUNT(*) FROM user_plugin_optouts WHERE marketplace_id = ?",
            [marketplace_id],
        ).fetchone()[0]
        self.conn.execute(
            "DELETE FROM user_plugin_optouts WHERE marketplace_id = ?",
            [marketplace_id],
        )
        return int(before)

    def fanout_system_for_plugin(
        self, marketplace_id: str, plugin_name: str,
    ) -> int:
        """Subscribe every existing user to ``(marketplace_id, plugin_name)``.

        Counterpart to ``fanout_system_for_user`` — this side picks one
        plugin and walks every user, that side picks one user and walks
        every system plugin. Both go through the same
        ``user_plugin_optouts`` PK + ``ON CONFLICT DO NOTHING`` so they
        compose freely with the user/group-create hooks.

        Returns the count of NEW subscriptions written (delta of
        before/after row counts) so the admin endpoint can report
        ``affected_users`` honestly — re-running on an already-marked
        plugin returns 0 instead of misleadingly reporting "every user".
        """
        before = self.conn.execute(
            "SELECT COUNT(*) FROM user_plugin_optouts "
            "WHERE marketplace_id = ? AND plugin_name = ?",
            [marketplace_id, plugin_name],
        ).fetchone()[0]
        self.conn.execute(
            """INSERT INTO user_plugin_optouts
               (user_id, marketplace_id, plugin_name)
               SELECT id, ?, ? FROM users
               ON CONFLICT (user_id, marketplace_id, plugin_name) DO NOTHING""",
            [marketplace_id, plugin_name],
        )
        after = self.conn.execute(
            "SELECT COUNT(*) FROM user_plugin_optouts "
            "WHERE marketplace_id = ? AND plugin_name = ?",
            [marketplace_id, plugin_name],
        ).fetchone()[0]
        return max(0, int(after) - int(before))

    def fanout_system_for_user(self, user_id: str) -> None:
        """Subscribe ``user_id`` to every ``is_system=TRUE`` marketplace_plugin.

        Idempotent — the table's PRIMARY KEY ``(user_id, marketplace_id,
        plugin_name)`` plus ``ON CONFLICT … DO NOTHING`` keeps existing
        subscriptions untouched.

        Called from two places:
        * the admin ``mark_system`` endpoint (one plugin × every existing
          user, with the SELECT-side filter still walking all system
          plugins — symmetric with ``fanout_system_for_group``)
        * the user-create hooks (Google OAuth, magic-link, admin-create,
          scheduler token) so a new user lands in the mandatory tier
          without an admin reconcile.
        """
        self.conn.execute(
            """INSERT INTO user_plugin_optouts
               (user_id, marketplace_id, plugin_name)
               SELECT ?, marketplace_id, name
               FROM marketplace_plugins WHERE is_system = TRUE
               ON CONFLICT (user_id, marketplace_id, plugin_name) DO NOTHING""",
            [user_id],
        )
