"""Rig Card screen for shareable system summary."""

from __future__ import annotations

from typing import TYPE_CHECKING
from datetime import datetime

from textual.screen import Screen
from textual.containers import Container, ScrollableContainer
from textual.widgets import Static, Footer
from rich.text import Text
from rich.style import Style

if TYPE_CHECKING:
    from ..providers.base import GPUHistory
    from ..system_info import SystemInfo, SystemMetrics


def render_bar_ascii(ratio: float, width: int = 30) -> str:
    """Render an ASCII progress bar."""
    ratio = max(0.0, min(1.0, ratio))
    filled = int(width * ratio)
    empty = width - filled
    return "\u2588" * filled + "\u2591" * empty


def generate_rig_card(
    sys_info: "SystemInfo | None",
    sys_metrics: "SystemMetrics | None",
    gpus: dict[int, "GPUHistory"],
) -> str:
    """Generate the shareable rig card text."""
    W = 58  # Content width (excluding borders)

    def line(content: str = "") -> str:
        """Create a bordered line with exact width."""
        # Pad or truncate to exact width
        if len(content) < W:
            content = content + " " * (W - len(content))
        elif len(content) > W:
            content = content[:W]
        return "\u2551" + content + "\u2551"

    def sep() -> str:
        """Create a horizontal separator."""
        return "\u2551" + "\u2500" * W + "\u2551"

    lines = []

    # Top border
    lines.append("\u2554" + "\u2550" * W + "\u2557")
    lines.append(line())

    # Logo
    lines.append(line("P  I  C  O  M  O  N".center(W)))
    lines.append(line("GPU Monitoring TUI".center(W)))

    lines.append(line())
    lines.append(sep())
    lines.append(line())

    # System info
    if sys_info:
        hostname = sys_info.hostname[:40] if len(sys_info.hostname) > 40 else sys_info.hostname
        lines.append(line(f"   SYSTEM      {hostname}"))

        cpu_short = sys_info.cpu_model
        if len(cpu_short) > 40:
            cpu_short = cpu_short[:37] + "..."
        lines.append(line(f"   CPU         {cpu_short}"))

        ram_str = f"{sys_info.ram_total_gb:.0f} GB"
        lines.append(line(f"   RAM         {ram_str}"))
    else:
        lines.append(line("   SYSTEM      Unknown"))

    lines.append(line())
    lines.append(sep())
    lines.append(line())

    # GPU Cluster info
    if gpus:
        num_gpus = len(gpus)
        lines.append(line("   GPU CLUSTER"))
        lines.append(line("   " + "\u2500" * 40))

        # Get GPU names (group by name)
        gpu_names = {}
        for h in gpus.values():
            name = h.name if h.name else "GPU"
            gpu_names[name] = gpu_names.get(name, 0) + 1
        gpu_desc = ", ".join(f"{count} \u00d7 {name}" for name, count in gpu_names.items())
        if len(gpu_desc) > 50:
            gpu_desc = f"{num_gpus} \u00d7 GPU"
        lines.append(line(f"   {gpu_desc}"))

        # Calculate totals
        total_vram_mb = sum(h.vram_total_mb for h in gpus.values())
        total_vram_gb = total_vram_mb / 1024
        per_gpu_vram = total_vram_gb / num_gpus

        total_tdp = sum(h.power_limit_w for h in gpus.values())
        per_gpu_tdp = total_tdp / num_gpus

        lines.append(line())
        lines.append(line(f"   VRAM        {total_vram_gb:.0f} GB ({per_gpu_vram:.0f} GB \u00d7 {num_gpus})"))
        lines.append(line(f"   TDP         {total_tdp:.0f} W ({per_gpu_tdp:.0f} W \u00d7 {num_gpus})"))

        lines.append(line())
        lines.append(sep())
        lines.append(line())

        # Live stats
        total_power = sum(h.power_w[-1] if h.power_w else 0 for h in gpus.values())
        total_vram_used = sum(h.vram_used_mb[-1] if h.vram_used_mb else 0 for h in gpus.values())
        avg_gfx = sum(h.gfx[-1] if h.gfx else 0 for h in gpus.values()) / num_gpus

        lines.append(line("   LIVE STATS"))
        lines.append(line("   " + "\u2500" * 40))

        # GFX bar
        gfx_bar = render_bar_ascii(avg_gfx / 100.0, 30)
        lines.append(line(f"   GPU Load    {gfx_bar} {avg_gfx:5.1f}%"))

        # Power bar
        pwr_ratio = total_power / total_tdp if total_tdp > 0 else 0
        pwr_bar = render_bar_ascii(pwr_ratio, 30)
        lines.append(line(f"   Power Draw  {pwr_bar} {total_power:5.0f}W"))

        # VRAM bar
        vram_ratio = total_vram_used / total_vram_mb if total_vram_mb > 0 else 0
        vram_bar = render_bar_ascii(vram_ratio, 30)
        vram_used_gb = total_vram_used / 1024
        lines.append(line(f"   VRAM Used   {vram_bar} {vram_used_gb:5.0f}GB"))

    else:
        lines.append(line("   No GPUs detected"))

    lines.append(line())
    lines.append("\u2551" + "\u2550" * W + "\u2551")

    # Footer
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M")
    lines.append(line(f"   Generated by picomon | {timestamp}"))

    # Bottom border
    lines.append("\u255a" + "\u2550" * W + "\u255d")

    return "\n".join(lines)


def generate_compact_card(
    sys_info: "SystemInfo | None",
    gpus: dict[int, "GPUHistory"],
) -> str:
    """Generate a more compact shareable card."""
    W = 44  # Content width

    def line(content: str = "") -> str:
        """Create a bordered line with exact width."""
        if len(content) < W:
            content = content + " " * (W - len(content))
        elif len(content) > W:
            content = content[:W]
        return "\u2502" + content + "\u2502"

    def sep() -> str:
        """Create a horizontal separator."""
        return "\u2502" + "\u2500" * W + "\u2502"

    lines = []

    lines.append("\u256d" + "\u2500" * W + "\u256e")
    lines.append(line("P I C O M O N".center(W)))
    lines.append(sep())

    if sys_info:
        hostname = sys_info.hostname[:40] if len(sys_info.hostname) > 40 else sys_info.hostname
        lines.append(line(f"  {hostname}"))
        cpu_short = sys_info.cpu_model[:28] if len(sys_info.cpu_model) > 28 else sys_info.cpu_model
        lines.append(line(f"  {cpu_short} | {sys_info.ram_total_gb:.0f} GB RAM"))

    lines.append(sep())

    if gpus:
        num_gpus = len(gpus)
        total_vram_gb = sum(h.vram_total_mb for h in gpus.values()) / 1024
        total_tdp = sum(h.power_limit_w for h in gpus.values())

        # Get first GPU name
        first_name = next((h.name for h in gpus.values() if h.name), "GPU")
        if len(first_name) > 20:
            first_name = first_name[:17] + "..."
        lines.append(line(f"  {num_gpus} \u00d7 {first_name}"))
        lines.append(line(f"  {total_vram_gb:.0f} GB VRAM | {total_tdp:.0f} W TDP"))

        lines.append(sep())

        # Live stats
        avg_gfx = sum(h.gfx[-1] if h.gfx else 0 for h in gpus.values()) / num_gpus
        total_power = sum(h.power_w[-1] if h.power_w else 0 for h in gpus.values())
        total_vram_used = sum(h.vram_used_mb[-1] if h.vram_used_mb else 0 for h in gpus.values()) / 1024

        gfx_bar = render_bar_ascii(avg_gfx / 100.0, 24)
        lines.append(line(f"  GFX  {gfx_bar} {avg_gfx:4.0f}%"))

        pwr_ratio = total_power / total_tdp if total_tdp > 0 else 0
        pwr_bar = render_bar_ascii(pwr_ratio, 24)
        lines.append(line(f"  PWR  {pwr_bar} {total_power:4.0f}W"))

        vram_ratio = total_vram_used / total_vram_gb if total_vram_gb > 0 else 0
        vram_bar = render_bar_ascii(vram_ratio, 24)
        if total_vram_used >= 1000:
            vram_str = f"{total_vram_used/1024:.1f}TB"
        else:
            vram_str = f"{total_vram_used:.0f}GB"
        lines.append(line(f"  VRAM {vram_bar} {vram_str:>5}"))

    lines.append("\u2570" + "\u2500" * W + "\u256f")

    return "\n".join(lines)


class RigCardHeader(Static):
    """Header for rig card screen."""

    DEFAULT_CSS = """
    RigCardHeader {
        dock: top;
        height: 3;
        background: #16213e;
        border-bottom: solid #e94560;
        padding: 0 2;
    }
    """

    def __init__(self, compact_mode: bool = False):
        super().__init__()
        self._compact_mode = compact_mode

    def set_mode(self, compact: bool):
        self._compact_mode = compact
        self.refresh()

    def render(self) -> Text:
        text = Text()
        mode = "Compact" if self._compact_mode else "Full"
        text.append("PICOMON", style=Style(color="#e94560", bold=True))
        text.append(f"  Rig Card ({mode})\n", style=Style(color="#888888"))
        text.append("[c] copy  [s] save  [m] toggle mode  [ESC] back", style=Style(color="#666666"))
        return text


class RigCardPreview(Static):
    """Preview of the rig card."""

    DEFAULT_CSS = """
    RigCardPreview {
        margin: 2;
        padding: 1;
        background: #16213e;
        border: double #e94560;
    }
    """

    def __init__(
        self,
        sys_info: "SystemInfo | None" = None,
        sys_metrics: "SystemMetrics | None" = None,
        gpus: dict[int, "GPUHistory"] | None = None,
        compact_mode: bool = False,
    ):
        super().__init__()
        self._sys_info = sys_info
        self._sys_metrics = sys_metrics
        self._gpus = gpus or {}
        self._compact_mode = compact_mode

    def set_mode(self, compact: bool):
        self._compact_mode = compact
        self.refresh()

    def get_card_text(self) -> str:
        """Get the current card text."""
        if self._compact_mode:
            return generate_compact_card(self._sys_info, self._gpus)
        else:
            return generate_rig_card(self._sys_info, self._sys_metrics, self._gpus)

    def render(self) -> Text:
        card_text = self.get_card_text()
        return Text(card_text, style=Style(color="#eaeaea"))


class RigCardActions(Static):
    """Actions bar for rig card screen."""

    DEFAULT_CSS = """
    RigCardActions {
        dock: bottom;
        height: 2;
        background: #16213e;
        border-top: solid #0f3460;
        padding: 0 2;
        content-align: center middle;
    }
    """

    def render(self) -> Text:
        text = Text()
        text.append("[c]", style=Style(color="#16c79a", bold=True))
        text.append(" Copy to clipboard  ", style=Style(color="#888888"))
        text.append("[s]", style=Style(color="#16c79a", bold=True))
        text.append(" Save to file  ", style=Style(color="#888888"))
        text.append("[m]", style=Style(color="#16c79a", bold=True))
        text.append(" Toggle mode  ", style=Style(color="#888888"))
        text.append("[ESC]", style=Style(color="#16c79a", bold=True))
        text.append(" Back", style=Style(color="#888888"))
        return text


class RigCardScreen(Screen):
    """Screen for displaying and copying the rig card."""

    BINDINGS = [
        ("q", "quit", "Quit"),
        ("c", "copy", "Copy"),
        ("s", "save", "Save"),
        ("m", "toggle_mode", "Toggle Mode"),
        ("escape", "back", "Back"),
        ("1", "dashboard", "Dashboard"),
    ]

    CSS = """
    RigCardScreen {
        background: #1a1a2e;
    }

    #rig-card-scroll {
        align: center middle;
    }
    """

    def __init__(
        self,
        sys_info: "SystemInfo | None" = None,
        sys_metrics: "SystemMetrics | None" = None,
        gpus: dict[int, "GPUHistory"] | None = None,
    ) -> None:
        super().__init__()
        self._sys_info = sys_info
        self._sys_metrics = sys_metrics
        self._gpus = gpus or {}
        self._compact_mode = False
        self._header: RigCardHeader | None = None
        self._preview: RigCardPreview | None = None

    def compose(self):
        """Compose the rig card screen."""
        self._header = RigCardHeader(self._compact_mode)
        yield self._header

        with ScrollableContainer(id="rig-card-scroll"):
            self._preview = RigCardPreview(
                self._sys_info,
                self._sys_metrics,
                self._gpus,
                self._compact_mode,
            )
            yield self._preview

        yield RigCardActions()
        yield Footer()

    def _get_card_text(self) -> str:
        """Get the current card text."""
        if self._preview:
            return self._preview.get_card_text()
        if self._compact_mode:
            return generate_compact_card(self._sys_info, self._gpus)
        else:
            return generate_rig_card(self._sys_info, self._sys_metrics, self._gpus)

    def action_copy(self) -> None:
        """Copy rig card to clipboard."""
        try:
            import pyperclip
            card_text = self._get_card_text()
            pyperclip.copy(card_text)
            self.notify("Copied to clipboard!", severity="information")
        except Exception as e:
            self.notify(f"Copy failed: {e}", severity="error")

    def action_save(self) -> None:
        """Save rig card to file."""
        try:
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            filename = f"picomon_rig_{timestamp}.txt"
            card_text = self._get_card_text()
            with open(filename, "w") as f:
                f.write(card_text)
            self.notify(f"Saved to {filename}", severity="information")
        except Exception as e:
            self.notify(f"Save failed: {e}", severity="error")

    def action_toggle_mode(self) -> None:
        """Toggle between full and compact mode."""
        self._compact_mode = not self._compact_mode
        if self._header:
            self._header.set_mode(self._compact_mode)
        if self._preview:
            self._preview.set_mode(self._compact_mode)

    def action_quit(self) -> None:
        """Quit the application."""
        self.app.exit()

    def action_back(self) -> None:
        """Go back."""
        self.app.pop_screen()

    def action_dashboard(self) -> None:
        """Go to dashboard."""
        self.app.switch_screen("dashboard")

    def refresh_data(self) -> None:
        """Refresh the rig card data."""
        if self._preview:
            self._preview.refresh()
