import random
import re

from django.core.exceptions import ValidationError
from django.utils.text import slugify

HANDLE_MIN_LENGTH = 3
HANDLE_MAX_LENGTH = 32
HANDLE_REGEX = re.compile(r"^[a-z0-9]+(?:-[a-z0-9]+)*$")

RESERVED_HANDLES = frozenset({
    "about",
    "about-us",
    "access",
    "access-token",
    "account",
    "account-settings",
    "accounts",
    "activate",
    "activation",
    "admin",
    "admin-console",
    "admin-panel",
    "admin-portal",
    "administrator",
    "advertise",
    "advertising",
    "affiliate",
    "affiliates",
    "agent",
    "agents",
    "api",
    "api-docs",
    "api-key",
    "api-keys",
    "api-v1",
    "api-v2",
    "api-v3",
    "app",
    "app-store",
    "apple-touch-icon",
    "apps",
    "assets",
    "audit",
    "audits",
    "auth",
    "auth-callback",
    "authorize",
    "avatar",
    "avatars",
    "backup",
    "backups",
    "beta",
    "billing",
    "billing-portal",
    "blog",
    "brand",
    "brand-assets",
    "brand-kit",
    "branding",
    "callback",
    "careers",
    "cart",
    "case-studies",
    "cdn",
    "changelog",
    "checkout",
    "claim",
    "clear-signup-tracking",
    "cloud",
    "community",
    "company",
    "compare",
    "components",
    "config",
    "configuration",
    "confirm",
    "confirmation",
    "connect",
    "console",
    "contact",
    "contact-us",
    "cookie-policy",
    "cookies",
    "copyright",
    "create",
    "credits",
    "css",
    "customer",
    "customers",
    "d",
    "dashboard",
    "data",
    "dev",
    "developer",
    "developer-portal",
    "developers",
    "directory",
    "discover",
    "dns",
    "docs",
    "download",
    "downloads",
    "early-access",
    "enterprise",
    "event",
    "events",
    "example",
    "examples",
    "explore",
    "faq",
    "favicon",
    "favicon-ico",
    "feature",
    "features",
    "feed",
    "feedback",
    "feeds",
    "file",
    "files",
    "find",
    "fonts",
    "forgot-password",
    "form",
    "forms",
    "g",
    "gallery",
    "gdpr",
    "get-started",
    "getting-started",
    "gobii",
    "gobii-ai",
    "gobiiapp",
    "guide",
    "guides",
    "health",
    "healthz",
    "help",
    "help-center",
    "helpdesk",
    "hire",
    "home",
    "images",
    "img",
    "incident",
    "incidents",
    "index",
    "insight",
    "insights",
    "integration",
    "integrations",
    "internal",
    "invite",
    "invite-only",
    "invites",
    "jobs",
    "join",
    "js",
    "kb",
    "keys",
    "learn",
    "legal",
    "legal-notice",
    "library",
    "license",
    "licenses",
    "login",
    "logout",
    "m",
    "manifest",
    "manifest-json",
    "marketplace",
    "mcp",
    "media",
    "metrics",
    "mfa",
    "moderator",
    "monitoring",
    "new",
    "news",
    "newsletter",
    "notifications",
    "oauth",
    "oauth-callback",
    "oauth2",
    "oidc",
    "onboarding",
    "openapi",
    "order",
    "orders",
    "org",
    "organization",
    "organizations",
    "orgs",
    "owner",
    "partner",
    "partners",
    "password",
    "password-forgot",
    "password-reset",
    "pay",
    "payment",
    "payments",
    "permissions",
    "plan",
    "plans",
    "platform",
    "press",
    "press-kit",
    "press-room",
    "pressroom",
    "pretrained-workers",
    "preview",
    "pricing",
    "privacy",
    "privacy-policy",
    "product",
    "products",
    "profile",
    "project",
    "projects",
    "prompt",
    "prompts",
    "public",
    "public-profile",
    "public-profiles",
    "public-template",
    "public-templates",
    "queue",
    "queues",
    "rate-limit",
    "redirect",
    "redirects",
    "reference",
    "referral",
    "referrals",
    "refresh-token",
    "register",
    "release",
    "releases",
    "report",
    "reports",
    "reseller",
    "resellers",
    "reset",
    "resources",
    "roadmap",
    "robots",
    "robots-txt",
    "role",
    "roles",
    "root",
    "rss",
    "saml",
    "sample",
    "samples",
    "sandbox",
    "scim",
    "scopes",
    "search",
    "security",
    "service",
    "services",
    "session",
    "sessions",
    "settings",
    "setup",
    "sign-in",
    "sign-out",
    "signin",
    "signout",
    "signup",
    "sitemap",
    "sitemap-xml",
    "solutions",
    "sso",
    "staff",
    "staging",
    "static",
    "status",
    "status-page",
    "statuspage",
    "stripe",
    "subscribe",
    "subscription",
    "subscriptions",
    "support",
    "support-center",
    "support-portal",
    "survey",
    "sys",
    "system",
    "tag",
    "tags",
    "task",
    "tasks",
    "team",
    "template",
    "template-gallery",
    "templates",
    "terms",
    "terms-of-service",
    "token",
    "tokens",
    "tos",
    "tracking",
    "trial",
    "trust",
    "tutorial",
    "tutorials",
    "u",
    "update",
    "upgrade",
    "uploads",
    "uptime",
    "usage",
    "user",
    "user-guide",
    "users",
    "verification",
    "verify",
    "waitlist",
    "web",
    "webapp",
    "webhook",
    "webhooks",
    "webinar",
    "webinars",
    "welcome",
    "workspace",
    "workspaces",
    "www",
})

ADJECTIVES = [
    "bright",
    "calm",
    "clever",
    "curious",
    "daring",
    "gentle",
    "keen",
    "lively",
    "lucid",
    "mighty",
    "nimble",
    "playful",
    "quiet",
    "quick",
    "radar",
    "sharp",
    "steady",
    "swift",
    "vivid",
    "wise",
]

NOUNS = [
    "atlas",
    "beacon",
    "comet",
    "compass",
    "drift",
    "ember",
    "glade",
    "harbor",
    "horizon",
    "isle",
    "kernel",
    "lighthouse",
    "orbit",
    "river",
    "signal",
    "spark",
    "summit",
    "tide",
    "vector",
    "voyage",
]


def normalize_public_handle(value: str) -> str:
    return slugify(value or "")


def is_reserved_handle(handle: str) -> bool:
    return handle in RESERVED_HANDLES


def validate_public_handle(value: str) -> str:
    normalized = normalize_public_handle(value)
    if not normalized:
        raise ValidationError("Handle is required.")
    if len(normalized) < HANDLE_MIN_LENGTH:
        raise ValidationError(f"Handle must be at least {HANDLE_MIN_LENGTH} characters.")
    if len(normalized) > HANDLE_MAX_LENGTH:
        raise ValidationError(f"Handle must be at most {HANDLE_MAX_LENGTH} characters.")
    if not HANDLE_REGEX.match(normalized):
        raise ValidationError("Handle may only include lowercase letters, numbers, and hyphens.")
    if is_reserved_handle(normalized):
        raise ValidationError("That handle is reserved.")
    return normalized


def generate_handle_suggestion() -> str:
    base = f"{random.choice(ADJECTIVES)}-{random.choice(NOUNS)}"
    if len(base) > HANDLE_MAX_LENGTH:
        base = base[:HANDLE_MAX_LENGTH].rstrip("-")
    return base


def with_handle_suffix(base: str, suffix: int) -> str:
    if suffix <= 1:
        return base
    suffix_text = f"-{suffix}"
    max_base_len = HANDLE_MAX_LENGTH - len(suffix_text)
    trimmed = base[:max_base_len].rstrip("-")
    if not trimmed:
        trimmed = base[:HANDLE_MAX_LENGTH].rstrip("-")
    return f"{trimmed}{suffix_text}"
