"""
DSS Core Sync

Syncs the canonical DSS Figma (shadcn/ui) to the DSS core tokens.
This is the base layer that all skins and projects inherit from.
"""

import json
import logging
import os
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, Optional

from dss.project.core import (
    DSS_FIGMA_REFERENCE,
    DSS_CORE_DIR,
    DSS_CACHE_DIR,
    DSS_CORE_THEMES,
    ensure_dss_directories,
)
from dss.project.figma import FigmaProjectSync, FigmaStyleData

logger = logging.getLogger(__name__)


class DSSCoreSync:
    """
    Syncs the DSS core design system from Figma.

    The shadcn/ui Figma file is the canonical source for:
    - Color tokens (light/dark themes)
    - Typography scale
    - Spacing scale
    - Component definitions
    - Effects (shadows, etc.)
    """

    def __init__(self, figma_token: Optional[str] = None):
        """
        Initialize DSS core sync.

        Args:
            figma_token: Figma token. Uses FIGMA_TOKEN env var if not provided.
        """
        self.figma_token = figma_token or os.environ.get("FIGMA_TOKEN")
        self.reference = DSS_FIGMA_REFERENCE
        ensure_dss_directories()

    @property
    def core_manifest_path(self) -> Path:
        """Path to DSS core manifest file."""
        return DSS_CORE_DIR / "manifest.json"

    @property
    def core_tokens_path(self) -> Path:
        """Path to DSS core tokens file."""
        return DSS_CORE_DIR / "tokens.json"

    @property
    def core_themes_path(self) -> Path:
        """Path to DSS core themes file."""
        return DSS_CORE_DIR / "themes.json"

    @property
    def core_components_path(self) -> Path:
        """Path to DSS core components file."""
        return DSS_CORE_DIR / "components.json"

    def get_sync_status(self) -> Dict[str, Any]:
        """Get current sync status."""
        manifest = self._load_manifest()

        return {
            "synced": manifest is not None,
            "last_sync": manifest.get("last_sync") if manifest else None,
            "figma_reference": {
                "team_id": self.reference.team_id,
                "project_id": self.reference.project_id,
                "uikit_file_key": self.reference.uikit_file_key,
                "uikit_file_name": self.reference.uikit_file_name,
            },
            "core_dir": str(DSS_CORE_DIR),
            "files": {
                "manifest": self.core_manifest_path.exists(),
                "tokens": self.core_tokens_path.exists(),
                "themes": self.core_themes_path.exists(),
                "components": self.core_components_path.exists(),
            }
        }

    def sync(self, force: bool = False) -> Dict[str, Any]:
        """
        Sync DSS core from Figma.

        Args:
            force: Force sync even if recently synced

        Returns:
            Sync result with extracted data summary
        """
        if not self.figma_token:
            return {
                "success": False,
                "error": "FIGMA_TOKEN not configured. Set env var or pass token."
            }

        # Check if sync needed
        manifest = self._load_manifest()
        if manifest and not force:
            last_sync = manifest.get("last_sync")
            if last_sync:
                # Could add time-based check here
                pass

        try:
            # Initialize Figma sync
            figma = FigmaProjectSync(token=self.figma_token)

            # Extract styles from UIKit file
            logger.info(f"Syncing from Figma: {self.reference.uikit_file_name}")
            styles = figma.get_file_styles(self.reference.uikit_file_key)

            # Process and save tokens
            tokens = self._process_tokens(styles)
            self._save_tokens(tokens)

            # Save themes (combine Figma + defaults)
            themes = self._process_themes(styles)
            self._save_themes(themes)

            # Save components
            components = self._process_components(styles)
            self._save_components(components)

            # Update manifest
            self._save_manifest(styles)

            return {
                "success": True,
                "message": f"Synced DSS core from {self.reference.uikit_file_name}",
                "summary": {
                    "colors": len(styles.colors),
                    "typography": len(styles.typography),
                    "effects": len(styles.effects),
                    "variables": len(styles.variables),
                },
                "files_written": [
                    str(self.core_manifest_path),
                    str(self.core_tokens_path),
                    str(self.core_themes_path),
                    str(self.core_components_path),
                ]
            }

        except Exception as e:
            logger.exception("DSS core sync failed")
            return {"success": False, "error": str(e)}

    def _process_tokens(self, styles: FigmaStyleData) -> Dict[str, Any]:
        """Process Figma styles into DSS token format."""
        tokens = {
            "version": "1.0.0",
            "source": "figma",
            "figma_file": self.reference.uikit_file_key,
            "synced_at": datetime.now().isoformat(),
            "categories": {}
        }

        # Colors
        tokens["categories"]["color"] = {}
        for path, data in styles.colors.items():
            tokens["categories"]["color"][path] = {
                "value": None,  # Value comes from variables or manual mapping
                "figma_id": data.get("figma_id"),
                "description": data.get("description", ""),
            }

        # Add variables as color tokens (they have actual values)
        for path, data in styles.variables.items():
            if data.get("type") == "COLOR":
                tokens["categories"]["color"][path] = {
                    "value": data.get("values", {}),
                    "figma_id": data.get("figma_id"),
                    "type": "variable",
                }

        # Typography
        tokens["categories"]["typography"] = {}
        for path, data in styles.typography.items():
            tokens["categories"]["typography"][path] = {
                "value": None,
                "figma_id": data.get("figma_id"),
                "name": data.get("name"),
            }

        # Effects (shadows, blurs)
        tokens["categories"]["effect"] = {}
        for path, data in styles.effects.items():
            tokens["categories"]["effect"][path] = {
                "value": None,
                "figma_id": data.get("figma_id"),
                "name": data.get("name"),
            }

        return tokens

    def _process_themes(self, styles: FigmaStyleData) -> Dict[str, Any]:
        """Process themes, merging Figma data with DSS defaults."""
        themes = {
            "version": "1.0.0",
            "source": "dss-core",
            "synced_at": datetime.now().isoformat(),
            "themes": {}
        }

        # Start with DSS core defaults
        for theme_name, theme_data in DSS_CORE_THEMES.items():
            themes["themes"][theme_name] = {
                "description": theme_data["description"],
                "colors": theme_data["colors"].copy(),
                "source": "dss-defaults",
            }

        # Overlay any Figma variables that map to themes
        # (Figma variables can have modes like light/dark)
        for path, data in styles.variables.items():
            values_by_mode = data.get("values", {})
            for mode_id, value in values_by_mode.items():
                # Try to map mode to theme
                # This is simplified - real implementation would use Figma mode names
                pass

        return themes

    def _process_components(self, styles: FigmaStyleData) -> Dict[str, Any]:
        """Extract component information from Figma."""
        from dss.project.core import DSS_CORE_COMPONENTS

        components = {
            "version": "1.0.0",
            "source": "dss-core",
            "synced_at": datetime.now().isoformat(),
            "components": {}
        }

        # Start with DSS core component definitions
        for name, comp_data in DSS_CORE_COMPONENTS.items():
            components["components"][name] = {
                "variants": comp_data.get("variants", []),
                "source": "dss-core",
            }

        return components

    def _load_manifest(self) -> Optional[Dict[str, Any]]:
        """Load existing manifest if present."""
        if self.core_manifest_path.exists():
            try:
                with open(self.core_manifest_path, "r") as f:
                    return json.load(f)
            except Exception:
                return None
        return None

    def _save_manifest(self, styles: FigmaStyleData):
        """Save sync manifest."""
        manifest = {
            "version": "1.0.0",
            "last_sync": datetime.now().isoformat(),
            "figma_reference": {
                "team_id": self.reference.team_id,
                "team_name": self.reference.team_name,
                "project_id": self.reference.project_id,
                "project_name": self.reference.project_name,
                "uikit_file_key": self.reference.uikit_file_key,
                "uikit_file_name": self.reference.uikit_file_name,
            },
            "stats": {
                "colors": len(styles.colors),
                "typography": len(styles.typography),
                "effects": len(styles.effects),
                "variables": len(styles.variables),
            }
        }

        with open(self.core_manifest_path, "w") as f:
            json.dump(manifest, f, indent=2)

    def _save_tokens(self, tokens: Dict[str, Any]):
        """Save tokens to file."""
        with open(self.core_tokens_path, "w") as f:
            json.dump(tokens, f, indent=2)

    def _save_themes(self, themes: Dict[str, Any]):
        """Save themes to file."""
        with open(self.core_themes_path, "w") as f:
            json.dump(themes, f, indent=2)

    def _save_components(self, components: Dict[str, Any]):
        """Save components to file."""
        with open(self.core_components_path, "w") as f:
            json.dump(components, f, indent=2)

    def get_tokens(self) -> Optional[Dict[str, Any]]:
        """Load synced tokens."""
        if self.core_tokens_path.exists():
            with open(self.core_tokens_path, "r") as f:
                return json.load(f)
        return None

    def get_themes(self) -> Optional[Dict[str, Any]]:
        """Load synced themes."""
        if self.core_themes_path.exists():
            with open(self.core_themes_path, "r") as f:
                return json.load(f)
        return None

    def get_components(self) -> Optional[Dict[str, Any]]:
        """Load synced components."""
        if self.core_components_path.exists():
            with open(self.core_components_path, "r") as f:
                return json.load(f)
        return None


# =============================================================================
# CONVENIENCE FUNCTIONS
# =============================================================================

def sync_dss_core(figma_token: Optional[str] = None, force: bool = False) -> Dict[str, Any]:
    """Sync DSS core from Figma."""
    sync = DSSCoreSync(figma_token=figma_token)
    return sync.sync(force=force)


def get_dss_core_status() -> Dict[str, Any]:
    """Get DSS core sync status."""
    sync = DSSCoreSync()
    return sync.get_sync_status()


def get_dss_core_tokens() -> Optional[Dict[str, Any]]:
    """Get DSS core tokens (must be synced first)."""
    sync = DSSCoreSync()
    return sync.get_tokens()


def get_dss_core_themes() -> Optional[Dict[str, Any]]:
    """Get DSS core themes."""
    sync = DSSCoreSync()
    return sync.get_themes()
