"""Watch — analyze shell history to find automation opportunities."""

from __future__ import annotations

import logging
import os
import re
from dataclasses import dataclass, field
from pathlib import Path

from rich.console import Console
from rich.panel import Panel
from rich.table import Table
from rich.text import Text

from alive.llm.base import LLMProvider

_log = logging.getLogger("alive")

HISTORY_LINES = 200


# ── Data structures ──────────────────────────────────────────────────────────


@dataclass
class SkillSuggestion:
    """A suggested skill based on shell history patterns."""

    name: str
    description: str
    pattern: str  # the repeated command pattern found
    frequency: str  # e.g. "ran 12 times in last 200 commands"
    build_command: str  # the alive build command to create it


# ── Shell history reading ────────────────────────────────────────────────────


def _find_history_file() -> Path | None:
    """Find the user's shell history file."""
    # Check HISTFILE env var first
    histfile = os.environ.get("HISTFILE")
    if histfile:
        p = Path(histfile)
        if p.exists():
            return p

    home = Path.home()
    candidates = [
        home / ".zsh_history",
        home / ".bash_history",
        home / ".local/share/fish/fish_history",
    ]

    for candidate in candidates:
        if candidate.exists() and candidate.stat().st_size > 0:
            return candidate

    return None


def _read_history(path: Path, n_lines: int = HISTORY_LINES) -> list[str]:
    """Read the last N lines of shell history.

    Handles zsh extended history format (: timestamp:0;command).
    """
    try:
        # Read with errors='replace' for encoding issues
        raw = path.read_text(errors="replace")
    except (OSError, PermissionError) as exc:
        _log.debug("Failed to read history file %s: %s", path, exc)
        return []

    lines = raw.strip().splitlines()

    # Take last N lines
    lines = lines[-n_lines:]

    # Clean up zsh extended history format
    cleaned = []
    for line in lines:
        line = line.strip()
        if not line:
            continue
        # zsh format: : 1234567890:0;actual command
        zsh_match = re.match(r"^:\s*\d+:\d+;(.+)$", line)
        if zsh_match:
            line = zsh_match.group(1)
        # fish format: - cmd: actual command
        fish_match = re.match(r"^-\s*cmd:\s*(.+)$", line)
        if fish_match:
            line = fish_match.group(1)
        cleaned.append(line.strip())

    return cleaned


# ── LLM analysis ─────────────────────────────────────────────────────────────

_WATCH_SYSTEM = """\
You are Alive's shell pattern analyzer. You find repeated command patterns \
in a user's shell history and suggest automations.

Given a list of recent shell commands, identify:
1. Commands or sequences that are repeated frequently
2. Multi-step workflows (e.g., git add + commit + push)
3. Complex one-liners that could be simplified

For each pattern found, respond with a block in this format:

```suggestion
name: descriptive_snake_case_name
description: One-line description of what the skill would do
pattern: The repeated command(s) found
frequency: How often this pattern appears (e.g., "8 times")
build_command: alive build "description for the skill builder"
```

Rules:
- Find 2-5 patterns maximum (only the most impactful ones)
- Ignore simple commands like cd, ls, cat, echo unless part of a workflow
- Ignore one-off commands — focus on REPETITION
- The build_command should describe the automation clearly
- Skip patterns involving sensitive data (passwords, tokens, etc.)
- If no meaningful patterns found, respond with: NO_PATTERNS_FOUND"""


async def analyze_history(
    *,
    provider: LLMProvider,
    n_lines: int = HISTORY_LINES,
) -> list[SkillSuggestion]:
    """Read shell history and ask LLM to find automation opportunities."""
    history_file = _find_history_file()
    if history_file is None:
        raise FileNotFoundError(
            "No shell history file found.\n\n"
            "Checked: ~/.zsh_history, ~/.bash_history, ~/.local/share/fish/fish_history\n"
            "Set HISTFILE env var if your history is elsewhere."
        )

    commands = _read_history(history_file, n_lines)
    if len(commands) < 5:
        raise ValueError(
            f"Not enough history to analyze (found {len(commands)} commands).\n\n"
            f"Use your shell for a while and try again."
        )

    # Sanitize — redact potential secrets
    sanitized = _sanitize_commands(commands)

    user_prompt = (
        f"Shell: {history_file.name}\n"
        f"Last {len(sanitized)} commands:\n\n"
        + "\n".join(f"  {cmd}" for cmd in sanitized)
    )

    response = await provider.complete(_WATCH_SYSTEM, user_prompt)

    if "NO_PATTERNS_FOUND" in response:
        return []

    return _parse_suggestions(response)


def _sanitize_commands(commands: list[str]) -> list[str]:
    """Redact potential secrets from commands."""
    sanitized = []
    for cmd in commands:
        # Redact tokens, keys, passwords
        cmd = re.sub(
            r"(token|key|password|secret|api.?key|auth)\s*[=:]\s*\S+",
            r"\1=<REDACTED>",
            cmd,
            flags=re.IGNORECASE,
        )
        # Redact export of sensitive vars
        cmd = re.sub(
            r"export\s+(.*(?:TOKEN|KEY|SECRET|PASSWORD|PASS).*?)=\S+",
            r"export \1=<REDACTED>",
            cmd,
            flags=re.IGNORECASE,
        )
        sanitized.append(cmd)
    return sanitized


def _parse_suggestions(response: str) -> list[SkillSuggestion]:
    """Parse suggestion blocks from LLM response."""
    suggestions = []
    blocks = re.findall(r"```suggestion\s*\n(.*?)```", response, re.DOTALL)

    for block in blocks:
        fields: dict[str, str] = {}
        for line in block.strip().splitlines():
            if ":" in line:
                key, _, value = line.partition(":")
                fields[key.strip().lower()] = value.strip()

        name = fields.get("name", "")
        desc = fields.get("description", "")
        if not name or not desc:
            continue

        suggestions.append(SkillSuggestion(
            name=name,
            description=desc,
            pattern=fields.get("pattern", ""),
            frequency=fields.get("frequency", ""),
            build_command=fields.get("build_command", f'alive build "{desc}"'),
        ))

    return suggestions


# ── Display ──────────────────────────────────────────────────────────────────


def display_suggestions(
    suggestions: list[SkillSuggestion],
    console: Console | None = None,
) -> None:
    """Display skill suggestions as rich panels."""
    console = console or Console()

    if not suggestions:
        console.print(Panel(
            "[dim]No repeated patterns found in your recent history.[/]\n\n"
            "Keep using your shell and try again later.",
            title="[bold]No Patterns Found[/]",
            border_style="yellow",
        ))
        return

    console.print()
    console.print(
        f"[bold cyan]Found {len(suggestions)} automation "
        f"opportunit{'y' if len(suggestions) == 1 else 'ies'}:[/]"
    )

    for i, s in enumerate(suggestions, 1):
        console.print()
        console.print(Panel(
            f"[bold]{s.description}[/]\n\n"
            f"[bold]Pattern:[/] [cyan]{s.pattern}[/]\n"
            f"[bold]Frequency:[/] {s.frequency}\n\n"
            f"[bold]Build it:[/]\n  [green]{s.build_command}[/]",
            title=f"[bold yellow]#{i} {s.name}[/]",
            border_style="yellow",
            padding=(1, 2),
        ))

    console.print()
    console.print("[dim]Copy a build command above to create the skill.[/]")
