"""
DSS Status Dashboard - Comprehensive system status visualization

Provides a beautiful ASCII art dashboard that aggregates data from:
- DSSManager (system info, dependencies)
- Database stats (projects, components, styles)
- ActivityLog (recent activity)
- SyncHistory (sync operations)
- QuickWinFinder (improvement opportunities)

Expert-validated design with:
- Optimized database queries using LIMIT
- Modular render methods for maintainability
- Named constants for health score weights
- Dynamic terminal width support
"""

import shutil
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Any
from dataclasses import dataclass, field

# Health score weight constants (expert recommendation)
HEALTH_WEIGHT_DEPENDENCIES = 0.40
HEALTH_WEIGHT_INTEGRATIONS = 0.25
HEALTH_WEIGHT_DATABASE = 0.20
HEALTH_WEIGHT_ACTIVITY = 0.15


@dataclass
class HealthMetric:
    """Individual health check result."""
    name: str
    status: str  # ok, warning, error
    value: str
    category: str = "general"
    details: Optional[str] = None


@dataclass
class StatusData:
    """Aggregated status data container."""
    version: str = ""
    healthy: bool = True
    health_score: int = 0
    mode: str = "unknown"
    timestamp: str = ""

    # Health metrics
    health_metrics: List[HealthMetric] = field(default_factory=list)

    # Design system metrics
    projects_count: int = 0
    projects_active: int = 0
    components_count: int = 0
    styles_count: int = 0
    tokens_count: int = 0
    adoption_percent: int = 0

    # Activity
    recent_activity: List[Dict] = field(default_factory=list)
    recent_syncs: List[Dict] = field(default_factory=list)
    total_activities: int = 0

    # Quick wins
    quick_wins_count: int = 0
    quick_wins: List[str] = field(default_factory=list)

    # Configuration
    project_root: str = ""
    database_path: str = ""
    cache_dir: str = ""
    figma_configured: bool = False
    anthropic_configured: bool = False

    # Recommendations
    recommendations: List[str] = field(default_factory=list)


class StatusDashboard:
    """
    Generates comprehensive DSS status dashboard.

    Aggregates data from multiple sources and presents it as either:
    - ASCII art dashboard for CLI (render_text())
    - JSON structure for programmatic access (get_status())
    """

    def __init__(self):
        """Initialize dashboard with lazy loading."""
        self._data: Optional[StatusData] = None
        self._settings = None
        self._manager = None

    def _ensure_initialized(self):
        """Lazy initialization of DSS components."""
        if self._settings is None:
            from dss.settings import DSSSettings, DSSManager
            self._settings = DSSSettings()
            self._manager = DSSManager(self._settings)

    def get_status(self) -> Dict[str, Any]:
        """
        Get full status as dictionary.

        Returns:
            Dict with all status information
        """
        data = self._gather_data()
        return {
            "success": True,
            "version": data.version,
            "healthy": data.healthy,
            "health_score": data.health_score,
            "mode": data.mode,
            "timestamp": data.timestamp,
            "health": [
                {"name": m.name, "status": m.status, "value": m.value, "category": m.category}
                for m in data.health_metrics
            ],
            "metrics": {
                "projects": {"total": data.projects_count, "active": data.projects_active},
                "components": data.components_count,
                "styles": data.styles_count,
                "tokens": data.tokens_count,
                "adoption_percent": data.adoption_percent
            },
            "activity": {
                "recent": data.recent_activity,
                "total": data.total_activities,
                "recent_syncs": data.recent_syncs
            },
            "quick_wins": {
                "count": data.quick_wins_count,
                "items": data.quick_wins
            },
            "configuration": {
                "project_root": data.project_root,
                "database": data.database_path,
                "cache": data.cache_dir,
                "figma_configured": data.figma_configured,
                "anthropic_configured": data.anthropic_configured
            },
            "recommendations": data.recommendations
        }

    def _gather_data(self) -> StatusData:
        """Aggregate data from all sources."""
        self._ensure_initialized()

        data = StatusData()

        # Version and timestamp
        from dss import __version__
        data.version = __version__
        data.timestamp = datetime.now().isoformat()

        # System info
        info = self._manager.get_system_info()
        data.project_root = info["project_root"]
        data.database_path = info["database_path"]
        data.cache_dir = info["cache_dir"]
        data.figma_configured = info["has_figma_token"]
        data.anthropic_configured = info["has_anthropic_key"]
        data.mode = "Mock APIs" if info["use_mock_apis"] else "Live"

        # Dependencies health
        deps = self._manager.check_dependencies()
        for dep, ok in deps.items():
            data.health_metrics.append(HealthMetric(
                name=dep,
                status="ok" if ok else "error",
                value="Installed" if ok else "Missing",
                category="dependency"
            ))

        # Integration health
        data.health_metrics.append(HealthMetric(
            name="Figma",
            status="ok" if data.figma_configured else "warning",
            value="Connected" if data.figma_configured else "No token",
            category="integration"
        ))
        data.health_metrics.append(HealthMetric(
            name="Anthropic",
            status="ok" if data.anthropic_configured else "warning",
            value="Connected" if data.anthropic_configured else "No key",
            category="integration"
        ))

        # Database stats
        try:
            from storage.json_store import get_stats, ActivityLog, SyncHistory, Projects, Components

            stats = get_stats()
            data.projects_count = stats.get("projects", 0)
            data.components_count = stats.get("components", 0)
            data.styles_count = stats.get("styles", 0)

            # Database size metric
            db_size = stats.get("db_size_mb", 0)
            data.health_metrics.append(HealthMetric(
                name="Database",
                status="ok" if db_size < 100 else "warning",
                value=f"{db_size} MB",
                category="database"
            ))

            # Projects
            projects = Projects.list()
            data.projects_active = len([p for p in projects if p.get("status") == "active"])

            # Recent activity (OPTIMIZED: use limit parameter, not slice)
            # Expert recommendation: avoid [:5] slicing which fetches all records
            activities = ActivityLog.recent(limit=5)
            data.recent_activity = [
                {
                    "action": a.get("action", ""),
                    "description": a.get("description", ""),
                    "created_at": a.get("created_at", ""),
                    "category": a.get("category", "")
                }
                for a in activities
            ]
            data.total_activities = ActivityLog.count()

            # Recent syncs (OPTIMIZED: use limit parameter)
            syncs = SyncHistory.recent(limit=3)
            data.recent_syncs = [
                {
                    "sync_type": s.get("sync_type", ""),
                    "status": s.get("status", ""),
                    "items_synced": s.get("items_synced", 0),
                    "started_at": s.get("started_at", "")
                }
                for s in syncs
            ]

        except Exception as e:
            data.health_metrics.append(HealthMetric(
                name="Database",
                status="error",
                value=f"Error: {str(e)[:30]}",
                category="database"
            ))

        # Calculate health score
        data.health_score = self._calculate_health_score(data)
        data.healthy = data.health_score >= 70

        # Generate recommendations
        data.recommendations = self._generate_recommendations(data)

        return data

    def _calculate_health_score(self, data: StatusData) -> int:
        """
        Calculate overall health score (0-100).

        Uses weighted components:
        - Dependencies: 40%
        - Integrations: 25%
        - Database: 20%
        - Activity: 15%
        """
        # Dependencies score (40%)
        dep_metrics = [m for m in data.health_metrics if m.category == "dependency"]
        if dep_metrics:
            deps_ok = sum(1 for m in dep_metrics if m.status == "ok") / len(dep_metrics)
        else:
            deps_ok = 0

        # Integrations score (25%)
        int_metrics = [m for m in data.health_metrics if m.category == "integration"]
        if int_metrics:
            int_ok = sum(1 for m in int_metrics if m.status == "ok") / len(int_metrics)
        else:
            int_ok = 0

        # Database score (20%)
        db_metrics = [m for m in data.health_metrics if m.category == "database"]
        if db_metrics:
            db_ok = sum(1 for m in db_metrics if m.status == "ok") / len(db_metrics)
        else:
            db_ok = 0

        # Activity score (15%) - based on having recent data
        activity_ok = 1.0 if data.projects_count > 0 or data.components_count > 0 else 0.5

        # Weighted score using named constants
        score = (
            deps_ok * HEALTH_WEIGHT_DEPENDENCIES +
            int_ok * HEALTH_WEIGHT_INTEGRATIONS +
            db_ok * HEALTH_WEIGHT_DATABASE +
            activity_ok * HEALTH_WEIGHT_ACTIVITY
        ) * 100

        return int(score)

    def _generate_recommendations(self, data: StatusData) -> List[str]:
        """Generate actionable recommendations based on current state."""
        recs = []

        if not data.figma_configured:
            recs.append("Set FIGMA_TOKEN environment variable to enable live Figma sync")

        if not data.anthropic_configured:
            recs.append("Set ANTHROPIC_API_KEY for AI-powered design analysis")

        if data.projects_count == 0:
            recs.append("Run dss_analyze_project to scan your first codebase")

        if data.tokens_count == 0:
            recs.append("Extract design tokens with dss_extract_tokens")

        if data.components_count == 0 and data.projects_count > 0:
            recs.append("Run dss_audit_components to discover React components")

        # Check for missing dependencies
        for m in data.health_metrics:
            if m.category == "dependency" and m.status == "error":
                recs.append(f"Install missing dependency: {m.name}")

        return recs[:5]  # Limit to top 5 recommendations

    def render_text(self) -> str:
        """
        Render status as formatted ASCII art dashboard.

        Uses dynamic terminal width for responsive layout.

        Returns:
            Formatted string with ASCII art dashboard
        """
        data = self._gather_data()

        # Get terminal width (expert recommendation)
        term_width = shutil.get_terminal_size((80, 24)).columns
        width = min(term_width - 2, 70)  # Cap at 70 for readability

        lines = []
        lines.append(self._render_header(data, width))
        lines.append("")
        lines.append(self._render_health_panel(data, width))
        lines.append("")
        lines.append(self._render_metrics_panel(data, width))
        lines.append("")
        lines.append(self._render_activity_panel(data, width))
        lines.append("")
        lines.append(self._render_recommendations_panel(data, width))

        return "\n".join(lines)

    def _render_header(self, data: StatusData, width: int) -> str:
        """Render the header section."""
        health_icon = "\u2705" if data.healthy else "\u26a0\ufe0f"
        health_text = f"{health_icon} Healthy ({data.health_score}%)" if data.healthy else f"{health_icon} Issues ({data.health_score}%)"

        lines = []
        lines.append("\u2554" + "\u2550" * width + "\u2557")
        lines.append("\u2551" + "\U0001f3a8 DSS Status Dashboard".center(width) + "\u2551")
        lines.append("\u2560" + "\u2550" * width + "\u2563")

        version_line = f" Version: {data.version:<20} Status: {health_text}"
        lines.append("\u2551" + version_line.ljust(width) + "\u2551")

        mode_line = f" Mode: {data.mode:<25} Time: {data.timestamp[:19]}"
        lines.append("\u2551" + mode_line.ljust(width) + "\u2551")

        lines.append("\u255a" + "\u2550" * width + "\u255d")

        return "\n".join(lines)

    def _render_health_panel(self, data: StatusData, width: int) -> str:
        """Render the health panel section."""
        lines = []
        lines.append("\u250c" + "\u2500" * width + "\u2510")
        lines.append("\u2502" + " \U0001f3e5 SYSTEM HEALTH".ljust(width) + "\u2502")
        lines.append("\u251c" + "\u2500" * width + "\u2524")

        # Dependencies
        deps = [m for m in data.health_metrics if m.category == "dependency"]
        deps_line = " Dependencies: "
        for d in deps:
            icon = "\u2705" if d.status == "ok" else "\u274c"
            deps_line += f"{icon} {d.name}  "
        lines.append("\u2502" + deps_line[:width].ljust(width) + "\u2502")

        # Integrations
        ints = [m for m in data.health_metrics if m.category == "integration"]
        int_line = " Integrations: "
        for i in ints:
            icon = "\u2705" if i.status == "ok" else "\u26a0\ufe0f"
            int_line += f"{icon} {i.name} ({i.value})  "
        lines.append("\u2502" + int_line[:width].ljust(width) + "\u2502")

        # Database
        db = next((m for m in data.health_metrics if m.category == "database"), None)
        if db:
            db_icon = "\u2705" if db.status == "ok" else "\u26a0\ufe0f"
            db_line = f" Database:     {db_icon} {db.value}"
            lines.append("\u2502" + db_line.ljust(width) + "\u2502")

        lines.append("\u2514" + "\u2500" * width + "\u2518")

        return "\n".join(lines)

    def _render_metrics_panel(self, data: StatusData, width: int) -> str:
        """Render the design system metrics panel."""
        lines = []
        lines.append("\u250c" + "\u2500" * width + "\u2510")
        lines.append("\u2502" + " \U0001f4ca DESIGN SYSTEM METRICS".ljust(width) + "\u2502")
        lines.append("\u251c" + "\u2500" * width + "\u2524")

        lines.append("\u2502" + f" Projects:     {data.projects_count} total ({data.projects_active} active)".ljust(width) + "\u2502")
        lines.append("\u2502" + f" Components:   {data.components_count} tracked".ljust(width) + "\u2502")
        lines.append("\u2502" + f" Styles:       {data.styles_count} defined".ljust(width) + "\u2502")

        # Tokens
        if data.tokens_count > 0:
            lines.append("\u2502" + f" Tokens:       {data.tokens_count} extracted".ljust(width) + "\u2502")
        else:
            lines.append("\u2502" + " Tokens:       -- (run dss_extract_tokens)".ljust(width) + "\u2502")

        # Adoption progress bar
        if data.adoption_percent > 0:
            bar_width = 30
            filled = int(bar_width * data.adoption_percent / 100)
            bar = "\u2588" * filled + "\u2591" * (bar_width - filled)
            lines.append("\u2502" + f" Adoption:     [{bar}] {data.adoption_percent}%".ljust(width) + "\u2502")

        lines.append("\u2514" + "\u2500" * width + "\u2518")

        return "\n".join(lines)

    def _render_activity_panel(self, data: StatusData, width: int) -> str:
        """Render the recent activity panel."""
        lines = []
        lines.append("\u250c" + "\u2500" * width + "\u2510")
        lines.append("\u2502" + " \U0001f551 RECENT ACTIVITY".ljust(width) + "\u2502")
        lines.append("\u251c" + "\u2500" * width + "\u2524")

        if data.recent_activity:
            for activity in data.recent_activity[:3]:
                action = activity.get("action", "Unknown")
                desc = activity.get("description", "")[:40]
                created = activity.get("created_at", "")[:10]
                line = f" \u2022 {created} | {action}: {desc}"
                lines.append("\u2502" + line[:width].ljust(width) + "\u2502")
        else:
            lines.append("\u2502" + " No recent activity".ljust(width) + "\u2502")

        lines.append("\u2502" + "".ljust(width) + "\u2502")
        lines.append("\u2502" + f" Total activities: {data.total_activities}".ljust(width) + "\u2502")

        lines.append("\u2514" + "\u2500" * width + "\u2518")

        return "\n".join(lines)

    def _render_recommendations_panel(self, data: StatusData, width: int) -> str:
        """Render the recommendations panel."""
        if not data.recommendations:
            return ""

        lines = []
        lines.append("\u250c" + "\u2500" * width + "\u2510")
        lines.append("\u2502" + " \U0001f4a1 RECOMMENDED NEXT STEPS".ljust(width) + "\u2502")
        lines.append("\u251c" + "\u2500" * width + "\u2524")

        for i, rec in enumerate(data.recommendations[:4], 1):
            line = f" {i}. {rec}"
            # Truncate if too long
            if len(line) > width - 1:
                line = line[:width-4] + "..."
            lines.append("\u2502" + line.ljust(width) + "\u2502")

        lines.append("\u2514" + "\u2500" * width + "\u2518")

        return "\n".join(lines)


# Convenience function
def get_dashboard() -> StatusDashboard:
    """Get a StatusDashboard instance."""
    return StatusDashboard()


if __name__ == "__main__":
    # CLI test
    import sys

    dashboard = StatusDashboard()

    if len(sys.argv) > 1 and sys.argv[1] == "--json":
        import json
        print(json.dumps(dashboard.get_status(), indent=2))
    else:
        print(dashboard.render_text())
