"""Billing access policy - workspace-scoped subscription enforcement."""
from __future__ import annotations
from typing import Optional
from uuid import UUID

import structlog

from src.core.exceptions import PaymentRequiredError
from src.domain.billing.normalization import (
    normalized_billing_status_from_row,
    requires_payment_flag,
)
from src.domain.billing.repository import SubscriptionRepository
from src.domain.workspaces.repository import WorkspaceRepository

logger = structlog.get_logger()

# Billing statuses that allow full workspace access
ACTIVE_BILLING_STATUSES = frozenset({"active", "trialing"})


def workspace_has_active_billing(sub_status: Optional[str]) -> bool:
    """True if subscription status allows premium workspace access."""
    return sub_status in ACTIVE_BILLING_STATUSES if sub_status else False


class BillingAccessPolicy:
    """Evaluates workspace billing for access control (aligned with bootstrap /auth/me)."""

    def __init__(
        self,
        subscription_repo: SubscriptionRepository,
        workspace_repo: WorkspaceRepository,
    ):
        self._subscription_repo = subscription_repo
        self._workspace_repo = workspace_repo

    async def require_active_billing(self, workspace_id: UUID) -> None:
        """
        Block only when the workspace still **requires payment** (see ``requires_payment_flag``).

        Free tier (``selected_plan_slug=free``, no paid sub) is allowed. Paid Stripe states
        active/trialing still pass; past_due / unpaid / incomplete without resolution do not.
        """
        ws = await self._workspace_repo.get_by_id(workspace_id)
        if not ws:
            logger.info("workspace_blocked_missing", workspace_id=str(workspace_id))
            raise PaymentRequiredError(
                message="Workspace not found or billing unavailable.",
                workspace_id=str(workspace_id),
                billing_status="none",
            )
        sub = await self._subscription_repo.get_latest_for_workspace(workspace_id)
        billing_status = normalized_billing_status_from_row(sub)
        selected = getattr(ws, "selected_plan_slug", None)
        if requires_payment_flag(billing_status, selected):
            logger.info(
                "workspace_blocked_unpaid_billing",
                workspace_id=str(workspace_id),
                billing_status=billing_status,
            )
            raise PaymentRequiredError(
                message="Active subscription or valid free plan required for this workspace.",
                workspace_id=str(workspace_id),
                billing_status=billing_status,
            )

    async def get_billing_status(self, workspace_id: UUID) -> str:
        """Return latest subscription status, or ``none`` if no row."""
        sub = await self._subscription_repo.get_latest_for_workspace(workspace_id)
        return sub.status if sub else "none"
