"""
Base classes and data structures for code analysis.
"""

from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
from typing import List, Dict, Any, Optional, Set
from pathlib import Path


class QuickWinType(str, Enum):
    """Types of quick-win improvements."""
    INLINE_STYLE = "inline_style"           # Inline styles that can be extracted
    DUPLICATE_VALUE = "duplicate_value"     # Duplicate color/spacing values
    UNUSED_STYLE = "unused_style"           # Unused CSS/SCSS
    HARDCODED_VALUE = "hardcoded_value"     # Hardcoded values that should be tokens
    NAMING_INCONSISTENCY = "naming"         # Inconsistent naming patterns
    DEPRECATED_PATTERN = "deprecated"       # Deprecated styling patterns
    ACCESSIBILITY = "accessibility"         # A11y improvements
    PERFORMANCE = "performance"             # Performance improvements


class QuickWinPriority(str, Enum):
    """Priority levels for quick-wins."""
    CRITICAL = "critical"   # Must fix - breaking issues
    HIGH = "high"           # Should fix - significant improvement
    MEDIUM = "medium"       # Nice to fix - moderate improvement
    LOW = "low"             # Optional - minor improvement


class StylingApproach(str, Enum):
    """Detected styling approaches in a project."""
    CSS_MODULES = "css-modules"
    STYLED_COMPONENTS = "styled-components"
    EMOTION = "emotion"
    TAILWIND = "tailwind"
    INLINE_STYLES = "inline-styles"
    CSS_IN_JS = "css-in-js"
    SASS_SCSS = "sass-scss"
    LESS = "less"
    VANILLA_CSS = "vanilla-css"
    CSS_VARIABLES = "css-variables"


class Framework(str, Enum):
    """Detected UI frameworks."""
    REACT = "react"
    NEXT = "next"
    VUE = "vue"
    NUXT = "nuxt"
    ANGULAR = "angular"
    SVELTE = "svelte"
    SOLID = "solid"
    UNKNOWN = "unknown"


@dataclass
class Location:
    """Represents a location in source code."""
    file_path: str
    line: int
    column: int = 0
    end_line: Optional[int] = None
    end_column: Optional[int] = None

    def __str__(self) -> str:
        return f"{self.file_path}:{self.line}"

    def to_dict(self) -> Dict[str, Any]:
        return {
            "file": self.file_path,
            "line": self.line,
            "column": self.column,
            "end_line": self.end_line,
            "end_column": self.end_column,
        }


@dataclass
class StyleFile:
    """Represents a style file in the project."""
    path: str
    type: str                          # css, scss, less, styled, etc.
    size_bytes: int = 0
    line_count: int = 0
    variable_count: int = 0
    selector_count: int = 0
    imports: List[str] = field(default_factory=list)
    imported_by: List[str] = field(default_factory=list)

    def to_dict(self) -> Dict[str, Any]:
        return {
            "path": self.path,
            "type": self.type,
            "size_bytes": self.size_bytes,
            "line_count": self.line_count,
            "variable_count": self.variable_count,
            "selector_count": self.selector_count,
            "imports": self.imports,
            "imported_by": self.imported_by,
        }


@dataclass
class ComponentInfo:
    """Information about a React component."""
    name: str
    path: str
    type: str = "functional"           # functional, class, forwardRef, memo
    props: List[str] = field(default_factory=list)
    has_styles: bool = False
    style_files: List[str] = field(default_factory=list)
    inline_style_count: int = 0
    imports: List[str] = field(default_factory=list)
    exports: List[str] = field(default_factory=list)
    children: List[str] = field(default_factory=list)  # Child components used
    line_count: int = 0

    def to_dict(self) -> Dict[str, Any]:
        return {
            "name": self.name,
            "path": self.path,
            "type": self.type,
            "props": self.props,
            "has_styles": self.has_styles,
            "style_files": self.style_files,
            "inline_style_count": self.inline_style_count,
            "imports": self.imports,
            "exports": self.exports,
            "children": self.children,
            "line_count": self.line_count,
        }


@dataclass
class StylePattern:
    """A detected style pattern in code."""
    type: StylingApproach
    locations: List[Location] = field(default_factory=list)
    count: int = 0
    examples: List[str] = field(default_factory=list)

    def to_dict(self) -> Dict[str, Any]:
        return {
            "type": self.type.value,
            "count": self.count,
            "locations": [loc.to_dict() for loc in self.locations[:10]],
            "examples": self.examples[:5],
        }


@dataclass
class TokenCandidate:
    """A value that could be extracted as a design token."""
    value: str                         # The actual value (e.g., "#3B82F6")
    suggested_name: str                # Suggested token name
    category: str                      # colors, spacing, typography, etc.
    occurrences: int = 1               # How many times it appears
    locations: List[Location] = field(default_factory=list)
    confidence: float = 0.0            # 0-1 confidence score

    def to_dict(self) -> Dict[str, Any]:
        return {
            "value": self.value,
            "suggested_name": self.suggested_name,
            "category": self.category,
            "occurrences": self.occurrences,
            "locations": [loc.to_dict() for loc in self.locations[:5]],
            "confidence": self.confidence,
        }


@dataclass
class QuickWin:
    """A quick improvement opportunity."""
    type: QuickWinType
    priority: QuickWinPriority
    title: str
    description: str
    location: Optional[Location] = None
    affected_files: List[str] = field(default_factory=list)
    estimated_impact: str = ""         # e.g., "Remove 50 lines of duplicate code"
    fix_suggestion: str = ""           # Suggested fix
    auto_fixable: bool = False         # Can be auto-fixed

    def to_dict(self) -> Dict[str, Any]:
        return {
            "type": self.type.value,
            "priority": self.priority.value,
            "title": self.title,
            "description": self.description,
            "location": self.location.to_dict() if self.location else None,
            "affected_files": self.affected_files,
            "estimated_impact": self.estimated_impact,
            "fix_suggestion": self.fix_suggestion,
            "auto_fixable": self.auto_fixable,
        }


@dataclass
class ProjectAnalysis:
    """Complete analysis result for a project."""
    # Basic info
    project_path: str
    analyzed_at: datetime = field(default_factory=datetime.now)

    # Framework detection
    framework: Framework = Framework.UNKNOWN
    framework_version: str = ""

    # Styling detection
    styling_approaches: List[StylePattern] = field(default_factory=list)
    primary_styling: Optional[StylingApproach] = None

    # Components
    components: List[ComponentInfo] = field(default_factory=list)
    component_count: int = 0

    # Style files
    style_files: List[StyleFile] = field(default_factory=list)
    style_file_count: int = 0

    # Issues and opportunities
    inline_style_locations: List[Location] = field(default_factory=list)
    token_candidates: List[TokenCandidate] = field(default_factory=list)
    quick_wins: List[QuickWin] = field(default_factory=list)

    # Dependency graph
    dependency_graph: Dict[str, List[str]] = field(default_factory=dict)

    # Statistics
    stats: Dict[str, Any] = field(default_factory=dict)

    def __post_init__(self):
        if not self.stats:
            self.stats = {
                "total_files_scanned": 0,
                "total_lines": 0,
                "component_count": 0,
                "style_file_count": 0,
                "inline_style_count": 0,
                "token_candidates": 0,
                "quick_wins_count": 0,
            }

    def to_dict(self) -> Dict[str, Any]:
        return {
            "project_path": self.project_path,
            "analyzed_at": self.analyzed_at.isoformat(),
            "framework": self.framework.value,
            "framework_version": self.framework_version,
            "styling_approaches": [sp.to_dict() for sp in self.styling_approaches],
            "primary_styling": self.primary_styling.value if self.primary_styling else None,
            "component_count": self.component_count,
            "style_file_count": self.style_file_count,
            "inline_style_count": len(self.inline_style_locations),
            "token_candidates_count": len(self.token_candidates),
            "quick_wins_count": len(self.quick_wins),
            "stats": self.stats,
        }

    def summary(self) -> str:
        """Generate human-readable summary."""
        lines = [
            f"Project Analysis: {self.project_path}",
            "=" * 50,
            f"Framework: {self.framework.value} {self.framework_version}",
            f"Components: {self.component_count}",
            f"Style files: {self.style_file_count}",
            "",
            "Styling Approaches:",
        ]

        for sp in self.styling_approaches:
            lines.append(f"  • {sp.type.value}: {sp.count} occurrences")

        lines.extend([
            "",
            f"Inline styles found: {len(self.inline_style_locations)}",
            f"Token candidates: {len(self.token_candidates)}",
            f"Quick wins: {len(self.quick_wins)}",
            "",
            "Quick Wins by Priority:",
        ])

        by_priority = {}
        for qw in self.quick_wins:
            if qw.priority not in by_priority:
                by_priority[qw.priority] = []
            by_priority[qw.priority].append(qw)

        for priority in [QuickWinPriority.CRITICAL, QuickWinPriority.HIGH,
                         QuickWinPriority.MEDIUM, QuickWinPriority.LOW]:
            if priority in by_priority:
                lines.append(f"  [{priority.value.upper()}] {len(by_priority[priority])} items")

        return "\n".join(lines)
