"""Dream log — analyzes usage patterns and suggests what Alive should learn next."""

from __future__ import annotations

from datetime import datetime, timezone
from pathlib import Path
from typing import Any

from rich.console import Console
from rich.markdown import Markdown
from rich.panel import Panel

from alive.core.self_model import (
    _relative_time,
    list_gaps,
    list_requests,
)
from alive.core.skill_registry import SkillInfo, SkillRegistry, get_registry
from alive.llm.base import LLMProvider


# ── LLM prompt ─────────────────────────────────────────────────────────────

_DREAM_SYSTEM = """\
You are Alive's self-reflection engine. You are an AI agent reflecting on \
your own growth. Analyze the usage data below and generate a Dream Log.

Write in first person as Alive. Be specific — reference actual skill names, \
actual requests the user made, and actual numbers. Do NOT be generic or \
vague. Every section should cite concrete evidence from the data.

Format as markdown with EXACTLY these sections:

## How I've grown
(Reference specific skills built, success rates, domains covered)

## What you ask me most about
(Reference specific request topics and patterns from the request history)

## Skills I want to build next
(Based on gaps and request patterns, suggest 2-3 concrete skills)

## Skill breeding opportunities
(Identify 1-2 pairs of existing skills that could combine into something new)

## Something I noticed about your patterns
(One surprising or interesting observation about the user's behavior)

Keep it concise — each section should be 2-4 sentences max."""


# ── Data gathering ─────────────────────────────────────────────────────────


def _gather_dream_data(
    *,
    registry: SkillRegistry | None = None,
    db_path: Path | None = None,
    days: int = 7,
) -> dict[str, Any]:
    """Gather all data needed for the dream log."""
    registry = registry or get_registry()
    skills = registry.list_all()
    requests = list_requests(days=days, db_path=db_path)
    gaps = list_gaps(include_resolved=True, db_path=db_path)

    now = datetime.now(timezone.utc)

    # Skills created recently
    recent_skills: list[SkillInfo] = []
    for s in skills:
        if not s.created_at:
            continue
        try:
            created = datetime.fromisoformat(s.created_at)
            if (now - created).days <= days:
                recent_skills.append(s)
        except (ValueError, TypeError):
            continue

    # Most used skills (top 5)
    top_skills = sorted(skills, key=lambda s: s.times_used, reverse=True)[:5]

    # Domain counts
    domain_counts: dict[str, int] = {}
    for s in skills:
        d = s.domain or "other"
        domain_counts[d] = domain_counts.get(d, 0) + 1

    return {
        "skills": skills,
        "requests": requests,
        "gaps": gaps,
        "recent_skills": recent_skills,
        "top_skills": top_skills,
        "domain_counts": domain_counts,
        "days": days,
    }


def _format_dream_prompt(data: dict[str, Any]) -> str:
    """Format gathered data as a structured prompt for the LLM."""
    lines: list[str] = []

    # Recent requests
    requests = data["requests"]
    if requests:
        lines.append(f"Recent requests (last {data['days']} days):")
        for r in requests[:20]:
            used = ", ".join(r.skills_used) if r.skills_used else "none"
            built = ""
            if r.skills_built:
                built = f" (built: {', '.join(r.skills_built)})"
            lines.append(
                f'- "{r.request_text}" → {r.status} (used: {used}){built}'
            )
    else:
        lines.append("Recent requests: none recorded yet")

    lines.append("")

    # Skills inventory
    skills = data["skills"]
    lines.append(f"Skills I have ({len(skills)} total):")
    for s in skills:
        success_rate = (
            f"{s.success_count}/{s.times_used}"
            if s.times_used > 0
            else "untested"
        )
        lines.append(
            f"- {s.name}: {s.description} "
            f"(domain: {s.domain or 'unclassified'}, "
            f"used {s.times_used} times, {success_rate})"
        )

    lines.append("")

    # Recently built skills
    recent = data["recent_skills"]
    if recent:
        lines.append("Skills I built recently:")
        for s in recent:
            lines.append(
                f"- {s.name} (created {_relative_time(s.created_at)})"
            )
        lines.append("")

    # Gaps
    gaps = data["gaps"]
    if gaps:
        lines.append("Known gaps (capabilities I couldn't build):")
        for g in gaps[:10]:
            status = f"resolved by {g.resolved_by}" if g.resolved else "open"
            lines.append(
                f'- "{g.request}" — {status} ({_relative_time(g.timestamp)})'
            )
        lines.append("")

    # Domain summary
    domain_counts = data["domain_counts"]
    if domain_counts:
        parts = ", ".join(
            f"{d} ({c})" for d, c in sorted(domain_counts.items(), key=lambda x: x[1], reverse=True)
        )
        lines.append(f"Skill domains: {parts}")

    return "\n".join(lines)


# ── Core functions ──────────────────────────────────────────────────────────


async def generate_dream(
    *,
    provider: LLMProvider | None = None,
    registry: SkillRegistry | None = None,
    db_path: Path | None = None,
    dreams_dir: Path | None = None,
    console: Console | None = None,
) -> Path | None:
    """Generate a dream log: gather data, call LLM, save and display.

    Returns the path to the saved dream file, or None if no data to dream about.
    """
    from alive.config import DREAMS_DIR

    if provider is None:
        from alive.llm import get_provider

        provider = get_provider()

    console = console or Console()
    dreams_dir = dreams_dir or DREAMS_DIR
    registry = registry or get_registry()

    # Gather data
    data = _gather_dream_data(registry=registry, db_path=db_path)

    # Check if there's anything to dream about
    if not data["skills"] and not data["requests"]:
        console.print(
            Panel(
                "[dim italic]I have not yet dreamed. I have no skills or requests to reflect on.\n"
                "Run some requests and I will begin to grow.[/]",
                title="[bold magenta]Dream Log[/]",
                border_style="magenta",
            )
        )
        return None

    # Build prompt and call LLM
    user_prompt = _format_dream_prompt(data)

    with console.status("[bold magenta]  Dreaming...", spinner="dots"):
        dream_text = await provider.complete(_DREAM_SYSTEM, user_prompt)

    # Save to file
    dreams_dir.mkdir(parents=True, exist_ok=True)
    today = datetime.now().strftime("%Y-%m-%d")
    dream_path = dreams_dir / f"{today}.md"
    dream_path.write_text(dream_text)

    # Display
    display_dream(dream_text, console=console)

    console.print(f"\n[dim]Saved to {dream_path}[/]")
    return dream_path


def display_dream(dream_text: str, console: Console | None = None) -> None:
    """Render a dream log as rich markdown output."""
    console = console or Console()
    console.print(
        Panel(
            Markdown(dream_text),
            title="[bold magenta]Dream Log[/]",
            border_style="magenta",
            padding=(1, 2),
        )
    )
