"""Profile statistics modal."""

import time

from rich.table import Table
from rich.text import Text

from textual.app import ComposeResult
from textual.binding import Binding
from textual.containers import Vertical, Horizontal, VerticalScroll
from textual.screen import ModalScreen
from textual.widgets import Static, Button

from claudechic.profiling import get_stats_table, get_stats_text, reset_stats, _stats
from claudechic.sampling import get_sampler, flatten, Episode


def _get_sampling_table() -> Table | None:
    """Get sampling profiler results as a Rich Table."""
    sampler = get_sampler()
    if sampler is None:
        return None

    profile = sampler.get_merged_profile()
    flat = flatten(profile, min_count=1)
    if not flat:
        return None

    stats = sampler.get_stats()
    table = Table(
        box=None,
        padding=(0, 2),
        collapse_padding=True,
        show_header=True,
        title=f"[dim]>{stats['threshold'] * 100:.0f}% threshold, {stats['sample_count']} samples[/]",
        title_justify="left",
    )
    table.add_column("Function", style="dim")
    table.add_column("File", style="dim")
    table.add_column("Line", justify="right")
    table.add_column("Count", justify="right")
    table.add_column("%", justify="right")

    total = profile["count"] or 1
    for _ident, count, desc in flat[:20]:  # Top 20
        pct = count / total * 100
        # Shorten filename
        filename = desc["filename"]
        if len(filename) > 30:
            filename = "..." + filename[-27:]
        table.add_row(
            desc["name"],
            filename,
            str(desc["line_number"]),
            str(count),
            f"{pct:.1f}%",
        )
    return table


def _get_sampling_text() -> str:
    """Get sampling data as plain text with full filenames."""
    sampler = get_sampler()
    if sampler is None:
        return ""

    profile = sampler.get_merged_profile()
    flat = flatten(profile, min_count=1)
    if not flat:
        return ""

    stats = sampler.get_stats()
    total = profile["count"] or 1
    lines = [
        f"\nCPU Samples (>{stats['threshold'] * 100:.0f}% threshold, {stats['sample_count']} samples)",
        "",
    ]
    for _ident, count, desc in flat[:30]:  # More entries for clipboard
        pct = count / total * 100
        lines.append(
            f"{desc['name']:30} {count:5} ({pct:5.1f}%)  {desc['filename']}:{desc['line_number']}"
        )
    return "\n".join(lines)


def _format_ago(t: float) -> str:
    """Format a timestamp as '42s ago' or '3m ago'."""
    delta = time.time() - t
    if delta < 60:
        return f"{delta:.0f}s ago"
    return f"{delta / 60:.0f}m ago"


def _format_episode(
    ep: Episode, index: int, indent: str = "", shorten_files: bool = False
) -> list[str]:
    """Format a single episode as lines of text."""
    lines = []
    cpu_info = f"avg {ep.avg_cpu * 100:.0f}%  peak {ep.peak_cpu * 100:.0f}%"
    lines.append(
        f"{indent}Episode {index}: {_format_ago(ep.end)}  {ep.duration:.1f}s  {cpu_info}"
    )
    if ep.lag_max > 0:
        lines.append(
            f"{indent}  Event loop lag: avg {ep.lag_mean * 1000:.0f}ms  max {ep.lag_max * 1000:.0f}ms"
        )
    if ep.text_chunks or ep.tool_uses or ep.tool_results:
        rate = ep.text_chunks / ep.duration if ep.duration > 0 else 0
        lines.append(
            f"{indent}  Messages: {ep.text_chunks} chunks ({rate:.0f}/s)  {ep.tool_uses} tool uses  {ep.tool_results} results"
        )
    hotspots = ep.hotspots
    if hotspots:
        total = ep.samples["count"] or 1
        lines.append(f"{indent}  Hotspots:")
        for _ident, count, desc in hotspots[:5]:
            pct = count / total * 100
            fname = desc["filename"]
            if shorten_files and len(fname) > 25:
                fname = "..." + fname[-22:]
            lines.append(
                f"{indent}    {desc['name']:25} {pct:5.1f}%  {fname}:{desc['line_number']}"
            )
    return lines


def _get_episodes_section() -> Text | None:
    """Get episode diagnostics as a Rich Text renderable."""
    sampler = get_sampler()
    if not sampler or not sampler.episodes:
        return None

    parts = Text()
    parts.append(f"({len(sampler.episodes)} recorded)\n\n", style="dim")

    for i, ep in enumerate(reversed(list(sampler.episodes))):
        if i > 0:
            parts.append("  ─────────────────────────────────────\n", style="dim")
        for line in _format_episode(ep, i + 1, indent="  ", shorten_files=True):
            parts.append(line + "\n", style="dim" if line.startswith("    ") else "")
        parts.append("\n")

    return parts


def _get_episodes_text() -> str:
    """Get episode data as plain text for clipboard."""
    sampler = get_sampler()
    if not sampler or not sampler.episodes:
        return ""

    lines = ["\nHigh-CPU Episodes", ""]
    for i, ep in enumerate(reversed(list(sampler.episodes))):
        lines.extend(_format_episode(ep, i + 1))
        lines.append("")
    return "\n".join(lines)


class ProfileModal(ModalScreen):
    """Modal showing profiling statistics."""

    BINDINGS = [
        Binding("escape", "dismiss", "Close"),
    ]

    DEFAULT_CSS = """
    ProfileModal {
        align: center middle;
    }

    ProfileModal #profile-container {
        width: auto;
        max-width: 90%;
        height: auto;
        max-height: 80%;
        background: $surface;
        border: solid $panel;
        padding: 1 2;
    }

    ProfileModal #profile-header {
        height: 1;
        margin-bottom: 1;
    }

    ProfileModal #profile-title {
        width: 1fr;
    }

    ProfileModal .copy-btn {
        width: 3;
        min-width: 3;
        height: 1;
        padding: 0;
        background: transparent;
        border: none;
        color: $text-muted;
    }

    ProfileModal .copy-btn:hover {
        color: $primary;
        background: transparent;
    }

    ProfileModal .section-header {
        height: 1;
        margin-top: 1;
    }

    ProfileModal .section-title {
        width: 1fr;
    }

    ProfileModal #profile-scroll {
        height: auto;
        max-height: 50;
    }

    ProfileModal #profile-content {
        height: auto;
    }

    ProfileModal #sampling-content {
        height: auto;
        margin-top: 1;
    }

    ProfileModal #episodes-content {
        height: auto;
        margin-top: 1;
    }

    ProfileModal #profile-footer {
        height: 1;
        margin-top: 1;
        align: center middle;
    }

    ProfileModal #close-btn {
        min-width: 10;
    }

    ProfileModal #reset-btn {
        min-width: 10;
        margin-right: 1;
    }
    """

    def compose(self) -> ComposeResult:
        with Vertical(id="profile-container"):
            with Horizontal(id="profile-header"):
                yield Static(
                    "[bold]Profiling Statistics[/]", id="profile-title", markup=True
                )
                yield Button("\u29c9", id="copy-all-btn", classes="copy-btn")
            with VerticalScroll(id="profile-scroll"):
                # Decorator profiling section
                if _stats:
                    with Horizontal(classes="section-header"):
                        yield Static(
                            "[bold]Decorator Profiling[/]",
                            classes="section-title",
                            markup=True,
                        )
                        yield Button(
                            "\u29c9", id="copy-profiling-btn", classes="copy-btn"
                        )
                    yield Static(get_stats_table(), id="profile-content")

                # Sampling profiler section
                sampling_table = _get_sampling_table()
                with Horizontal(classes="section-header"):
                    yield Static(
                        "[bold]CPU Samples[/]", classes="section-title", markup=True
                    )
                    yield Button("\u29c9", id="copy-sampling-btn", classes="copy-btn")
                if sampling_table:
                    yield Static(sampling_table, id="sampling-content")
                else:
                    yield Static(
                        "[dim]No CPU samples collected (CPU stayed below threshold).[/]",
                        id="sampling-content",
                        markup=True,
                    )

                # Episodes section
                episodes = _get_episodes_section()
                if episodes:
                    with Horizontal(classes="section-header"):
                        yield Static(
                            "[bold]High-CPU Episodes[/]",
                            classes="section-title",
                            markup=True,
                        )
                        yield Button(
                            "\u29c9", id="copy-episodes-btn", classes="copy-btn"
                        )
                    yield Static(episodes, id="episodes-content")

            with Horizontal(id="profile-footer"):
                yield Button("Reset", id="reset-btn")
                yield Button("Close", id="close-btn")

    def _copy_text(self, text: str) -> None:
        try:
            import pyperclip

            pyperclip.copy(text)
            self.notify("Copied to clipboard")
        except Exception as e:
            self.notify(f"Copy failed: {e}", severity="error")

    def on_button_pressed(self, event: Button.Pressed) -> None:
        if event.button.id == "copy-all-btn":
            self._copy_text(
                get_stats_text()
                + "\n"
                + _get_sampling_text()
                + "\n"
                + _get_episodes_text()
            )
        elif event.button.id == "copy-profiling-btn":
            self._copy_text(get_stats_text())
        elif event.button.id == "copy-sampling-btn":
            self._copy_text(_get_sampling_text())
        elif event.button.id == "copy-episodes-btn":
            self._copy_text(_get_episodes_text())
        elif event.button.id == "reset-btn":
            reset_stats()
            sampler = get_sampler()
            if sampler:
                sampler.reset()
            self.notify("Profiling stats reset")
            self.dismiss()
        elif event.button.id == "close-btn":
            self.dismiss()
