"""Org/repo/label bootstrap helpers (#44, #83)."""
from __future__ import annotations

from .core import GitHubError, _graphql


def get_organization_id(token: str, login: str) -> str | None:
    """Return the org's node ID, or None if the org does not exist.

    Distinguishes "org missing" from transient errors — orgs cannot be
    created via API, so the scaffold tool pauses with UI instructions
    rather than retrying when this returns None.
    """
    if not login.strip():
        raise ValueError("login must not be empty.")

    query = """
    query($login: String!) {
      organization(login: $login) { id }
    }
    """
    data = _graphql(token, query, {"login": login})
    org = data.get("organization")
    return org["id"] if org else None


def create_repository(
    token: str,
    owner_id: str,
    name: str,
    visibility: str,
    description: str = "",
) -> dict:
    """Create a repo under an org or user.

    `visibility` must be "PUBLIC" / "PRIVATE" / "INTERNAL" (GitHub's
    RepositoryVisibility enum).

    Returns: {"id": str, "url": str, "name_with_owner": str}
    """
    if not owner_id.strip() or not name.strip():
        raise ValueError("owner_id and name must not be empty.")
    if visibility not in ("PUBLIC", "PRIVATE", "INTERNAL"):
        raise ValueError(
            f"visibility must be PUBLIC / PRIVATE / INTERNAL, got: {visibility!r}"
        )

    query = """
    mutation(
      $ownerId: ID!, $name: String!,
      $visibility: RepositoryVisibility!, $description: String!
    ) {
      createRepository(input: {
        ownerId: $ownerId,
        name: $name,
        visibility: $visibility,
        description: $description
      }) {
        repository { id url nameWithOwner }
      }
    }
    """
    data = _graphql(
        token,
        query,
        {
            "ownerId": owner_id,
            "name": name,
            "visibility": visibility,
            "description": description,
        },
    )
    repo = (data.get("createRepository") or {}).get("repository") or {}
    return {
        "id": repo.get("id", ""),
        "url": repo.get("url", ""),
        "name_with_owner": repo.get("nameWithOwner", ""),
    }


def get_repo_discussions_state(token: str, repo_id: str) -> dict:
    """Return the repo's Discussions enablement and current categories.

    Returns:
        {
            "enabled": bool,
            "categories": {
                "<name>": {"id": str, "isAnswerable": bool},
                ...
            },
        }

    Discussion categories cannot be created via GraphQL — GitHub only
    exposes them for read. scaffold_project v2 uses this helper to
    detect whether the dev repo is ready for Phase B (seed Project +
    Session-Lock discussions).
    """
    if not repo_id.strip():
        raise ValueError("repo_id must not be empty.")

    query = """
    query($id: ID!) {
      node(id: $id) {
        ... on Repository {
          hasDiscussionsEnabled
          discussionCategories(first: 25) {
            nodes { id name isAnswerable }
          }
        }
      }
    }
    """
    data = _graphql(token, query, {"id": repo_id})
    node = data.get("node") or {}
    if not node:
        raise GitHubError(f"Repository {repo_id} not found.")
    enabled = bool(node.get("hasDiscussionsEnabled"))
    nodes = ((node.get("discussionCategories") or {}).get("nodes")) or []
    categories = {
        n["name"]: {"id": n["id"], "isAnswerable": bool(n.get("isAnswerable"))}
        for n in nodes
        if n.get("name")
    }
    return {"enabled": enabled, "categories": categories}


def enable_discussions(token: str, repo_id: str) -> bool:
    """Enable GitHub Discussions on a repository.

    Uses `updateRepository(hasDiscussionsEnabled: true)`. Safe to call
    when already enabled — GitHub accepts the mutation as a no-op.
    Returns True on success.
    """
    if not repo_id.strip():
        raise ValueError("repo_id must not be empty.")

    query = """
    mutation($repoId: ID!) {
      updateRepository(input: {
        repositoryId: $repoId,
        hasDiscussionsEnabled: true
      }) {
        repository { id hasDiscussionsEnabled }
      }
    }
    """
    _graphql(token, query, {"repoId": repo_id})
    return True


def create_label(
    token: str,
    repo_id: str,
    name: str,
    color: str = "ededed",
    description: str = "",
) -> str:
    """Create a label on a repo. Returns the label's node ID.

    Raises GitHubError if the label already exists (caller should
    catch and treat as idempotent).
    """
    if not repo_id.strip() or not name.strip():
        raise ValueError("repo_id and name must not be empty.")

    query = """
    mutation($repoId: ID!, $name: String!, $color: String!, $description: String) {
      createLabel(input: {
        repositoryId: $repoId, name: $name, color: $color, description: $description
      }) {
        label { id }
      }
    }
    """
    data = _graphql(
        token,
        query,
        {
            "repoId": repo_id,
            "name": name,
            "color": color,
            "description": description,
        },
    )
    label = (data.get("createLabel") or {}).get("label") or {}
    return label.get("id", "")
