"""
Design System Registry - Knowledge base of popular design systems.

This module provides:
- Built-in knowledge of 20+ popular design systems
- Fuzzy matching for user queries
- npm package information
- Alternative ingestion methods (Figma, CSS, docs)
"""

from dataclasses import dataclass, field
from typing import List, Optional, Dict, Any
from enum import Enum
import re


class IngestionMethod(Enum):
    """Available methods for ingesting design tokens."""
    NPM_PACKAGE = "npm_package"
    TAILWIND_CONFIG = "tailwind_config"
    CSS_VARIABLES = "css_variables"
    FIGMA = "figma"
    JSON_TOKENS = "json_tokens"
    SCSS_VARIABLES = "scss_variables"
    STYLE_DICTIONARY = "style_dictionary"


@dataclass
class DesignSystemInfo:
    """Information about a known design system."""
    id: str
    name: str
    description: str
    aliases: List[str] = field(default_factory=list)
    npm_packages: List[str] = field(default_factory=list)
    primary_ingestion: IngestionMethod = IngestionMethod.NPM_PACKAGE
    figma_community_url: Optional[str] = None
    docs_url: Optional[str] = None
    github_url: Optional[str] = None
    token_paths: List[str] = field(default_factory=list)  # Paths within npm package to tokens
    css_cdn_url: Optional[str] = None
    category: str = "component-library"
    framework: Optional[str] = None  # react, vue, angular, html, etc.

    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary for API responses."""
        return {
            "id": self.id,
            "name": self.name,
            "description": self.description,
            "aliases": self.aliases,
            "npm_packages": self.npm_packages,
            "primary_ingestion": self.primary_ingestion.value,
            "figma_community_url": self.figma_community_url,
            "docs_url": self.docs_url,
            "github_url": self.github_url,
            "token_paths": self.token_paths,
            "css_cdn_url": self.css_cdn_url,
            "category": self.category,
            "framework": self.framework,
        }


# Built-in registry of popular design systems
DESIGN_SYSTEMS: Dict[str, DesignSystemInfo] = {}


def register_system(system: DesignSystemInfo) -> None:
    """Register a design system in the registry."""
    DESIGN_SYSTEMS[system.id] = system


# =============================================================================
# Popular Design Systems Registry
# =============================================================================

# HeroUI (NextUI successor)
register_system(DesignSystemInfo(
    id="heroui",
    name="HeroUI",
    description="Beautiful, fast and modern React UI library (formerly NextUI)",
    aliases=["hero-ui", "hero ui", "nextui", "next-ui", "next ui"],
    npm_packages=["@heroui/react", "@heroui/theme"],
    primary_ingestion=IngestionMethod.TAILWIND_CONFIG,
    figma_community_url="https://www.figma.com/community/file/1267584376522720519",
    docs_url="https://www.heroui.com/docs",
    github_url="https://github.com/heroui-inc/heroui",
    token_paths=["@heroui/theme/dist/colors.js", "@heroui/theme/dist/default-layout.js"],
    category="component-library",
    framework="react",
))

# Shadcn/ui
register_system(DesignSystemInfo(
    id="shadcn",
    name="shadcn/ui",
    description="Beautifully designed components built with Radix UI and Tailwind CSS",
    aliases=["shadcn", "shadcn-ui", "shadcnui", "shad", "shad-cn"],
    npm_packages=["shadcn-ui"],  # CLI tool, components are copy-pasted
    primary_ingestion=IngestionMethod.CSS_VARIABLES,
    figma_community_url="https://www.figma.com/community/file/1203061493325953101",
    docs_url="https://ui.shadcn.com/docs",
    github_url="https://github.com/shadcn-ui/ui",
    token_paths=[],  # Tokens are in CSS variables
    css_cdn_url="https://ui.shadcn.com/registry/styles/default/index.json",
    category="component-library",
    framework="react",
))

# Material UI (MUI)
register_system(DesignSystemInfo(
    id="mui",
    name="Material UI",
    description="Google's Material Design implemented for React",
    aliases=["material-ui", "material ui", "materialui", "mui", "@mui"],
    npm_packages=["@mui/material", "@mui/system", "@emotion/react", "@emotion/styled"],
    primary_ingestion=IngestionMethod.NPM_PACKAGE,
    figma_community_url="https://www.figma.com/community/file/912837788133317724",
    docs_url="https://mui.com/material-ui/getting-started/",
    github_url="https://github.com/mui/material-ui",
    token_paths=["@mui/material/styles"],
    category="component-library",
    framework="react",
))

# Chakra UI
register_system(DesignSystemInfo(
    id="chakra",
    name="Chakra UI",
    description="Simple, modular and accessible component library for React",
    aliases=["chakra-ui", "chakra ui", "chakraui"],
    npm_packages=["@chakra-ui/react", "@chakra-ui/theme"],
    primary_ingestion=IngestionMethod.NPM_PACKAGE,
    figma_community_url="https://www.figma.com/community/file/971408767069651759",
    docs_url="https://chakra-ui.com/docs/getting-started",
    github_url="https://github.com/chakra-ui/chakra-ui",
    token_paths=["@chakra-ui/theme/dist/foundations"],
    category="component-library",
    framework="react",
))

# Ant Design
register_system(DesignSystemInfo(
    id="antd",
    name="Ant Design",
    description="Enterprise-class UI design language and React components",
    aliases=["ant-design", "ant design", "antdesign", "antd"],
    npm_packages=["antd", "@ant-design/icons"],
    primary_ingestion=IngestionMethod.NPM_PACKAGE,
    figma_community_url="https://www.figma.com/community/file/831698976089873405",
    docs_url="https://ant.design/docs/react/introduce",
    github_url="https://github.com/ant-design/ant-design",
    token_paths=["antd/dist/antd.variable.css"],
    css_cdn_url="https://unpkg.com/antd/dist/antd.variable.css",
    category="component-library",
    framework="react",
))

# Tailwind CSS
register_system(DesignSystemInfo(
    id="tailwind",
    name="Tailwind CSS",
    description="Utility-first CSS framework for rapid UI development",
    aliases=["tailwindcss", "tailwind css", "tw"],
    npm_packages=["tailwindcss"],
    primary_ingestion=IngestionMethod.TAILWIND_CONFIG,
    figma_community_url="https://www.figma.com/community/file/768809027799962739",
    docs_url="https://tailwindcss.com/docs",
    github_url="https://github.com/tailwindlabs/tailwindcss",
    token_paths=["tailwindcss/defaultTheme"],
    category="css-framework",
    framework="html",
))

# Bootstrap
register_system(DesignSystemInfo(
    id="bootstrap",
    name="Bootstrap",
    description="Popular HTML, CSS, and JS library for responsive design",
    aliases=["bootstrap5", "bootstrap 5", "bs", "bs5", "twbs"],
    npm_packages=["bootstrap"],
    primary_ingestion=IngestionMethod.SCSS_VARIABLES,
    figma_community_url="https://www.figma.com/community/file/876022745968684318",
    docs_url="https://getbootstrap.com/docs/5.3/getting-started/introduction/",
    github_url="https://github.com/twbs/bootstrap",
    token_paths=["bootstrap/scss/_variables.scss"],
    css_cdn_url="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css",
    category="css-framework",
    framework="html",
))

# Radix UI
register_system(DesignSystemInfo(
    id="radix",
    name="Radix UI",
    description="Unstyled, accessible components for building design systems",
    aliases=["radix-ui", "radix ui", "radixui", "@radix-ui"],
    npm_packages=["@radix-ui/themes", "@radix-ui/colors"],
    primary_ingestion=IngestionMethod.CSS_VARIABLES,
    figma_community_url="https://www.figma.com/community/file/1295954844895805217",
    docs_url="https://www.radix-ui.com/themes/docs/overview/getting-started",
    github_url="https://github.com/radix-ui/themes",
    token_paths=["@radix-ui/colors"],
    category="component-library",
    framework="react",
))

# Mantine
register_system(DesignSystemInfo(
    id="mantine",
    name="Mantine",
    description="React components library with native dark theme support",
    aliases=["mantine-ui", "mantineui"],
    npm_packages=["@mantine/core", "@mantine/hooks"],
    primary_ingestion=IngestionMethod.NPM_PACKAGE,
    figma_community_url="https://www.figma.com/community/file/1293978471602433537",
    docs_url="https://mantine.dev/getting-started/",
    github_url="https://github.com/mantinedev/mantine",
    token_paths=["@mantine/core/styles.css"],
    category="component-library",
    framework="react",
))

# Fluent UI (Microsoft)
register_system(DesignSystemInfo(
    id="fluent",
    name="Fluent UI",
    description="Microsoft's design system for building web experiences",
    aliases=["fluent-ui", "fluentui", "fluent ui", "@fluentui", "fabric"],
    npm_packages=["@fluentui/react-components", "@fluentui/tokens"],
    primary_ingestion=IngestionMethod.NPM_PACKAGE,
    figma_community_url="https://www.figma.com/community/file/836828295772957889",
    docs_url="https://react.fluentui.dev/",
    github_url="https://github.com/microsoft/fluentui",
    token_paths=["@fluentui/tokens"],
    category="component-library",
    framework="react",
))

# IBM Carbon
register_system(DesignSystemInfo(
    id="carbon",
    name="Carbon Design System",
    description="IBM's open source design system for products and experiences",
    aliases=["carbon-design", "ibm-carbon", "ibm carbon", "@carbon"],
    npm_packages=["@carbon/react", "@carbon/styles", "@carbon/colors"],
    primary_ingestion=IngestionMethod.SCSS_VARIABLES,
    figma_community_url="https://www.figma.com/community/file/1157761560874207208",
    docs_url="https://carbondesignsystem.com/",
    github_url="https://github.com/carbon-design-system/carbon",
    token_paths=["@carbon/colors", "@carbon/type", "@carbon/layout"],
    category="design-system",
    framework="react",
))

# Primer (GitHub)
register_system(DesignSystemInfo(
    id="primer",
    name="Primer",
    description="GitHub's design system with CSS and React components",
    aliases=["primer-css", "github-primer", "github primer", "@primer"],
    npm_packages=["@primer/react", "@primer/css", "@primer/primitives"],
    primary_ingestion=IngestionMethod.JSON_TOKENS,
    figma_community_url="https://www.figma.com/community/file/854767373644076713",
    docs_url="https://primer.style/",
    github_url="https://github.com/primer/primitives",
    token_paths=["@primer/primitives/dist/json"],
    category="design-system",
    framework="react",
))

# Spectrum (Adobe)
register_system(DesignSystemInfo(
    id="spectrum",
    name="Adobe Spectrum",
    description="Adobe's design system for creating seamless experiences",
    aliases=["adobe-spectrum", "adobe spectrum", "@spectrum", "@adobe/spectrum"],
    npm_packages=["@adobe/react-spectrum", "@spectrum-css/tokens"],
    primary_ingestion=IngestionMethod.JSON_TOKENS,
    figma_community_url="https://www.figma.com/community/file/1196015001498069893",
    docs_url="https://spectrum.adobe.com/",
    github_url="https://github.com/adobe/react-spectrum",
    token_paths=["@spectrum-css/tokens"],
    category="design-system",
    framework="react",
))

# Salesforce Lightning
register_system(DesignSystemInfo(
    id="lightning",
    name="Salesforce Lightning",
    description="Salesforce Lightning Design System for enterprise apps",
    aliases=["slds", "lightning-design", "salesforce-lightning", "salesforce lightning"],
    npm_packages=["@salesforce-ux/design-system"],
    primary_ingestion=IngestionMethod.SCSS_VARIABLES,
    figma_community_url="https://www.figma.com/community/file/877593312714992614",
    docs_url="https://www.lightningdesignsystem.com/",
    github_url="https://github.com/salesforce-ux/design-system",
    token_paths=["@salesforce-ux/design-system/design-tokens"],
    category="design-system",
    framework="html",
))

# Atlassian Design System
register_system(DesignSystemInfo(
    id="atlassian",
    name="Atlassian Design System",
    description="Atlassian's end-to-end design language for products",
    aliases=["atlaskit", "atlas-kit", "atlassian-design", "@atlaskit"],
    npm_packages=["@atlaskit/tokens", "@atlaskit/theme"],
    primary_ingestion=IngestionMethod.JSON_TOKENS,
    figma_community_url="https://www.figma.com/community/file/1189965498990866853",
    docs_url="https://atlassian.design/",
    github_url="https://bitbucket.org/atlassian/atlassian-frontend-mirror/src/master/",
    token_paths=["@atlaskit/tokens/dist/esm/artifacts/tokens-raw"],
    category="design-system",
    framework="react",
))

# Shopify Polaris
register_system(DesignSystemInfo(
    id="polaris",
    name="Shopify Polaris",
    description="Shopify's design system for building admin experiences",
    aliases=["shopify-polaris", "shopify polaris", "@shopify/polaris"],
    npm_packages=["@shopify/polaris", "@shopify/polaris-tokens"],
    primary_ingestion=IngestionMethod.JSON_TOKENS,
    figma_community_url="https://www.figma.com/community/file/1293611962331823010",
    docs_url="https://polaris.shopify.com/",
    github_url="https://github.com/Shopify/polaris",
    token_paths=["@shopify/polaris-tokens/dist/json"],
    category="design-system",
    framework="react",
))

# Vuetify
register_system(DesignSystemInfo(
    id="vuetify",
    name="Vuetify",
    description="Material Design component framework for Vue.js",
    aliases=["vuetify3", "vuetify 3"],
    npm_packages=["vuetify"],
    primary_ingestion=IngestionMethod.SCSS_VARIABLES,
    figma_community_url="https://www.figma.com/community/file/1181257898482695401",
    docs_url="https://vuetifyjs.com/en/getting-started/installation/",
    github_url="https://github.com/vuetifyjs/vuetify",
    token_paths=["vuetify/lib/styles/settings/_variables.scss"],
    category="component-library",
    framework="vue",
))

# PrimeVue / PrimeReact
register_system(DesignSystemInfo(
    id="primevue",
    name="PrimeVue",
    description="Rich set of open source UI components for Vue",
    aliases=["prime-vue", "prime vue", "primereact", "prime-react", "primefaces"],
    npm_packages=["primevue", "primeicons"],
    primary_ingestion=IngestionMethod.CSS_VARIABLES,
    figma_community_url="https://www.figma.com/community/file/890589747170608208",
    docs_url="https://primevue.org/",
    github_url="https://github.com/primefaces/primevue",
    token_paths=["primevue/resources/themes"],
    category="component-library",
    framework="vue",
))

# DaisyUI
register_system(DesignSystemInfo(
    id="daisyui",
    name="daisyUI",
    description="Tailwind CSS component library with semantic class names",
    aliases=["daisy-ui", "daisy ui", "daisy"],
    npm_packages=["daisyui"],
    primary_ingestion=IngestionMethod.TAILWIND_CONFIG,
    figma_community_url="https://www.figma.com/community/file/1098092815609260082",
    docs_url="https://daisyui.com/docs/install/",
    github_url="https://github.com/saadeghi/daisyui",
    token_paths=["daisyui/src/theming/themes.js"],
    category="component-library",
    framework="html",
))

# Headless UI
register_system(DesignSystemInfo(
    id="headlessui",
    name="Headless UI",
    description="Unstyled, accessible UI components for React and Vue",
    aliases=["headless-ui", "headless ui", "@headlessui"],
    npm_packages=["@headlessui/react", "@headlessui/vue"],
    primary_ingestion=IngestionMethod.CSS_VARIABLES,
    docs_url="https://headlessui.com/",
    github_url="https://github.com/tailwindlabs/headlessui",
    token_paths=[],  # Unstyled, no tokens
    category="component-library",
    framework="react",
))

# Open Props
register_system(DesignSystemInfo(
    id="openprops",
    name="Open Props",
    description="Supercharged CSS variables for design systems",
    aliases=["open-props", "open props"],
    npm_packages=["open-props"],
    primary_ingestion=IngestionMethod.CSS_VARIABLES,
    figma_community_url="https://www.figma.com/community/file/1144820109792924498",
    docs_url="https://open-props.style/",
    github_url="https://github.com/argyleink/open-props",
    token_paths=["open-props/open-props.min.css"],
    css_cdn_url="https://unpkg.com/open-props",
    category="css-tokens",
    framework="html",
))

# Pico CSS
register_system(DesignSystemInfo(
    id="picocss",
    name="Pico CSS",
    description="Minimal CSS framework for semantic HTML",
    aliases=["pico-css", "pico css", "pico"],
    npm_packages=["@picocss/pico"],
    primary_ingestion=IngestionMethod.CSS_VARIABLES,
    docs_url="https://picocss.com/docs/",
    github_url="https://github.com/picocss/pico",
    token_paths=["@picocss/pico/css/pico.css"],
    css_cdn_url="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css",
    category="css-framework",
    framework="html",
))

# Bulma
register_system(DesignSystemInfo(
    id="bulma",
    name="Bulma",
    description="Modern CSS framework based on Flexbox",
    aliases=["bulma-css", "bulma css"],
    npm_packages=["bulma"],
    primary_ingestion=IngestionMethod.SCSS_VARIABLES,
    figma_community_url="https://www.figma.com/community/file/1145794431179045801",
    docs_url="https://bulma.io/documentation/",
    github_url="https://github.com/jgthms/bulma",
    token_paths=["bulma/sass/utilities/_variables.scss"],
    css_cdn_url="https://cdn.jsdelivr.net/npm/bulma@1.0.0/css/bulma.min.css",
    category="css-framework",
    framework="html",
))


# =============================================================================
# Registry Search and Matching Functions
# =============================================================================

def normalize_query(query: str) -> str:
    """Normalize a search query for matching."""
    # Lowercase and remove special characters
    normalized = query.lower().strip()
    # Remove common prefixes
    normalized = re.sub(r'^(@|use |add |import |ingest |install )', '', normalized)
    # Remove common suffixes
    normalized = re.sub(r'( design system| ui| css| react| vue)$', '', normalized)
    # Remove special characters but keep hyphens
    normalized = re.sub(r'[^\w\s-]', '', normalized)
    # Collapse multiple spaces
    normalized = re.sub(r'\s+', ' ', normalized)
    return normalized.strip()


def find_design_system(query: str) -> Optional[DesignSystemInfo]:
    """
    Find a design system by name or alias.
    Returns the best match or None if not found.
    """
    normalized = normalize_query(query)

    # Exact match on ID
    if normalized in DESIGN_SYSTEMS:
        return DESIGN_SYSTEMS[normalized]

    # Exact match on aliases
    for system in DESIGN_SYSTEMS.values():
        if normalized in [a.lower() for a in system.aliases]:
            return system
        if normalized == system.name.lower():
            return system

    # Partial match on name or aliases
    for system in DESIGN_SYSTEMS.values():
        # Check if query is contained in system name
        if normalized in system.name.lower():
            return system
        # Check if query is contained in any alias
        for alias in system.aliases:
            if normalized in alias.lower():
                return system

    # Fuzzy match - check if any word matches
    query_words = set(normalized.split())
    best_match = None
    best_score = 0

    for system in DESIGN_SYSTEMS.values():
        # Create set of all searchable terms
        terms = {system.id.lower(), system.name.lower()}
        terms.update(a.lower() for a in system.aliases)

        # Count matching words
        for term in terms:
            term_words = set(term.split())
            matches = len(query_words & term_words)
            if matches > best_score:
                best_score = matches
                best_match = system

    if best_score > 0:
        return best_match

    return None


def search_design_systems(query: str, limit: int = 5) -> List[DesignSystemInfo]:
    """
    Search for design systems matching a query.
    Returns a list of matches sorted by relevance.
    """
    normalized = normalize_query(query)
    results = []

    for system in DESIGN_SYSTEMS.values():
        score = 0

        # Exact match on ID or name
        if normalized == system.id.lower() or normalized == system.name.lower():
            score = 100
        # Exact alias match
        elif normalized in [a.lower() for a in system.aliases]:
            score = 90
        # Partial match in name
        elif normalized in system.name.lower():
            score = 70
        # Partial match in aliases
        elif any(normalized in a.lower() for a in system.aliases):
            score = 60
        # Word overlap
        else:
            query_words = set(normalized.split())
            all_terms = {system.id, system.name} | set(system.aliases)
            all_words = set()
            for term in all_terms:
                all_words.update(term.lower().split())

            overlap = len(query_words & all_words)
            if overlap > 0:
                score = overlap * 20

        if score > 0:
            results.append((score, system))

    # Sort by score descending
    results.sort(key=lambda x: x[0], reverse=True)

    return [system for _, system in results[:limit]]


def get_all_systems() -> List[DesignSystemInfo]:
    """Get all registered design systems."""
    return list(DESIGN_SYSTEMS.values())


def get_systems_by_category(category: str) -> List[DesignSystemInfo]:
    """Get design systems filtered by category."""
    return [s for s in DESIGN_SYSTEMS.values() if s.category == category]


def get_systems_by_framework(framework: str) -> List[DesignSystemInfo]:
    """Get design systems filtered by framework."""
    return [s for s in DESIGN_SYSTEMS.values() if s.framework == framework]


# =============================================================================
# Alternative Ingestion Suggestions
# =============================================================================

def get_alternative_ingestion_options(system: Optional[DesignSystemInfo] = None) -> Dict[str, Any]:
    """
    Get alternative ingestion options when primary method is unavailable.
    """
    alternatives = {
        "figma": {
            "name": "Figma Import",
            "description": "Provide a Figma file URL to extract design tokens and components",
            "prompt": "Please provide the Figma file URL (e.g., https://www.figma.com/file/...)",
            "requires": "figma_url"
        },
        "css_url": {
            "name": "CSS/SCSS URL",
            "description": "Provide a URL to a CSS or SCSS file containing design tokens",
            "prompt": "Please provide the CSS/SCSS file URL",
            "requires": "css_url"
        },
        "image": {
            "name": "Image Analysis",
            "description": "Upload an image or screenshot of the design system for AI analysis",
            "prompt": "Please provide an image URL or upload a screenshot of your design system",
            "requires": "image_url"
        },
        "manual": {
            "name": "Manual Entry",
            "description": "Manually enter design tokens (colors, typography, spacing)",
            "prompt": "Describe your design tokens (e.g., 'primary color: #3b82f6, font: Inter')",
            "requires": "text_description"
        },
        "github": {
            "name": "GitHub Repository",
            "description": "Provide a GitHub repository URL containing design tokens",
            "prompt": "Please provide the GitHub repository URL",
            "requires": "github_url"
        }
    }

    # If we have a known system, customize suggestions
    if system:
        result = {"known_system": system.to_dict(), "alternatives": []}

        if system.figma_community_url:
            result["alternatives"].append({
                **alternatives["figma"],
                "suggested_url": system.figma_community_url
            })

        if system.css_cdn_url:
            result["alternatives"].append({
                **alternatives["css_url"],
                "suggested_url": system.css_cdn_url
            })

        if system.github_url:
            result["alternatives"].append({
                **alternatives["github"],
                "suggested_url": system.github_url
            })

        # Always offer manual and image options
        result["alternatives"].append(alternatives["image"])
        result["alternatives"].append(alternatives["manual"])

        return result

    # Unknown system - offer all alternatives
    return {
        "known_system": None,
        "alternatives": list(alternatives.values())
    }
