"""Report generation, visualization, working group analysis, and export commands."""

from __future__ import annotations

from pathlib import Path

import click
from rich.table import Table

from .common import console, pass_cfg_db, _get_config
from ..config import Config
from ..db import Database


def register(main):
    """Register all report/viz/wg/export commands with the main CLI group."""
    main.add_command(report)
    main.add_command(viz)
    main.add_command(wg)
    main.add_command(export)


# ── report ───────────────────────────────────────────────────────────────────


@click.group()
def report():
    """Generate markdown reports."""
    pass


@report.command()
@pass_cfg_db
def overview(cfg, db):
    """Overview table of all rated drafts."""
    from ..reports import Reporter
    path = Reporter(cfg, db).overview()
    console.print(f"Report saved: [bold]{path}[/]")


@report.command()
@pass_cfg_db
def landscape(cfg, db):
    """Category-grouped landscape view."""
    from ..reports import Reporter
    path = Reporter(cfg, db).landscape()
    console.print(f"Report saved: [bold]{path}[/]")


@report.command()
@click.option("--days", "-d", default=7, help="Look back N days")
@pass_cfg_db
def digest(cfg, db, days: int):
    """What's new digest."""
    from ..reports import Reporter
    path = Reporter(cfg, db).digest(since_days=days)
    console.print(f"Report saved: [bold]{path}[/]")


@report.command()
@pass_cfg_db
def timeline(cfg, db):
    """Timeline of draft submissions by month and category."""
    from ..reports import Reporter
    path = Reporter(cfg, db).timeline()
    console.print(f"Report saved: [bold]{path}[/]")


@report.command("overlap-matrix")
@pass_cfg_db
def overlap_matrix(cfg, db):
    """Full pairwise overlap matrix report."""
    from ..embeddings import Embedder
    from ..reports import Reporter
    embedder = Embedder(cfg, db)
    n_drafts = len(db.all_drafts())
    console.print(f"Computing {n_drafts}x{n_drafts} similarity matrix...")
    path = Reporter(cfg, db).overlap_matrix(embedder)
    console.print(f"Report saved: [bold]{path}[/]")


@report.command("authors")
@pass_cfg_db
def authors_report(cfg, db):
    """Author and organization network report."""
    from ..reports import Reporter
    path = Reporter(cfg, db).authors_report()
    console.print(f"Report saved: [bold]{path}[/]")


@report.command("ideas")
@pass_cfg_db
def ideas_report(cfg, db):
    """Report on extracted technical ideas."""
    from ..reports import Reporter
    path = Reporter(cfg, db).ideas_report()
    console.print(f"Report saved: [bold]{path}[/]")


@report.command("refs")
@pass_cfg_db
def refs_report(cfg, db):
    """Cross-reference report — which standards the ecosystem builds on."""
    from ..reports import Reporter
    path = Reporter(cfg, db).refs_report()
    console.print(f"Report saved: [bold]{path}[/]")


@report.command("trends")
@pass_cfg_db
def trends_report(cfg, db):
    """Category trend analysis report (markdown)."""
    from ..reports import Reporter
    path = Reporter(cfg, db).trends_report()
    console.print(f"Report saved: [bold]{path}[/]")


@report.command("idea-overlap")
@pass_cfg_db
def idea_overlap_report(cfg, db):
    """Cross-organization idea overlap report."""
    from ..reports import Reporter
    path = Reporter(cfg, db).idea_overlap_report()
    console.print(f"Report saved: [bold]{path}[/]")


@report.command("status")
@pass_cfg_db
def status_report(cfg, db):
    """WG adoption status report."""
    from ..reports import Reporter
    path = Reporter(cfg, db).status_report()
    console.print(f"Report saved: [bold]{path}[/]")


@report.command("revisions")
@pass_cfg_db
def revisions_report(cfg, db):
    """Draft revision velocity report."""
    from ..reports import Reporter
    path = Reporter(cfg, db).revisions_report()
    console.print(f"Report saved: [bold]{path}[/]")


@report.command("centrality")
@pass_cfg_db
def centrality_report(cfg, db):
    """Author network centrality report."""
    from ..reports import Reporter
    path = Reporter(cfg, db).centrality_report()
    console.print(f"Report saved: [bold]{path}[/]")


@report.command("co-occurrence")
@pass_cfg_db
def co_occurrence_report(cfg, db):
    """Category co-occurrence matrix report."""
    from ..reports import Reporter
    path = Reporter(cfg, db).co_occurrence_report()
    console.print(f"Report saved: [bold]{path}[/]")


@report.command("wg")
@pass_cfg_db
def wg_report(cfg, db):
    """Working group analysis report — overlaps, alignment, submission targets."""
    from ..reports import Reporter
    path = Reporter(cfg, db).wg_report()
    console.print(f"Report saved: [bold]{path}[/]")


@report.command("sources")
@pass_cfg_db
def sources_report(cfg, db):
    """Cross-source comparison report — ratings and categories by standards body."""
    from ..reports import Reporter
    path = Reporter(cfg, db).sources_report()
    console.print(f"Report saved: [bold]{path}[/]")


@report.command("false-positives")
@pass_cfg_db
def false_positives_report(cfg, db):
    """False positive profiling report — what makes drafts look AI-related but not be."""
    from ..reports import Reporter
    path = Reporter(cfg, db).false_positives_report()
    console.print(f"Report saved: [bold]{path}[/]")


@report.command("citations")
@pass_cfg_db
def citations_report(cfg, db):
    """Citation influence and BCP dependency analysis."""
    from ..reports import Reporter
    path = Reporter(cfg, db).citations_report()
    console.print(f"Report saved: [bold]{path}[/]")


@report.command("complexity")
@pass_cfg_db
def complexity_report(cfg, db):
    """Draft complexity matrix: correlations between structural complexity and ratings."""
    from ..reports import Reporter
    path = Reporter(cfg, db).complexity_report()
    console.print(f"Report saved: [bold]{path}[/]")


@report.command("idea-analysis")
@pass_cfg_db
def idea_analysis_report(cfg, db):
    """Idea novelty deep dive — distribution, types, top ideas, cross-draft patterns."""
    from ..reports import Reporter
    path = Reporter(cfg, db).idea_analysis()
    console.print(f"Report saved: [bold]{path}[/]")


# ── wg (working group analysis) ─────────────────────────────────────────


@click.group()
def wg():
    """Working group analysis — overlaps, alignment opportunities, submission targets."""
    pass


@wg.command("list")
@click.option("--min-drafts", default=1, help="Minimum drafts to show a WG")
@pass_cfg_db
def wg_list(cfg, db, min_drafts: int):
    """List working groups with draft counts and average scores."""
    summaries = db.wg_summary()
    if not summaries:
        console.print("[yellow]No WG data. Run: python scripts/backfill-wg-names.py[/]")
        return

    summaries = [s for s in summaries if s["draft_count"] >= min_drafts]

    table = Table(title=f"Working Groups ({len(summaries)} with >= {min_drafts} drafts)")
    table.add_column("WG", style="cyan", width=12)
    table.add_column("#", justify="right", width=4)
    table.add_column("Ideas", justify="right", width=5)
    table.add_column("Nov", justify="center", width=4)
    table.add_column("Mat", justify="center", width=4)
    table.add_column("Ovl", justify="center", width=4)
    table.add_column("Mom", justify="center", width=4)
    table.add_column("Rel", justify="center", width=4)
    table.add_column("Top Categories")

    for s in summaries:
        top_cats = sorted(s["categories"].items(), key=lambda x: x[1], reverse=True)[:3]
        cats_str = ", ".join(f"{c}({n})" for c, n in top_cats) if top_cats else "-"
        table.add_row(
            s["wg"], str(s["draft_count"]), str(s["idea_count"]),
            str(s["avg_novelty"]), str(s["avg_maturity"]),
            str(s["avg_overlap"]), str(s["avg_momentum"]),
            str(s["avg_relevance"]), cats_str,
        )

    console.print(table)

    # Also show individual submission count
    indiv = db.conn.execute(
        'SELECT COUNT(*) FROM drafts WHERE "group" = \'none\' OR "group" IS NULL'
    ).fetchone()[0]
    console.print(f"\n[dim]Individual submissions (no WG): {indiv}[/]")


@wg.command("show")
@click.argument("name")
@pass_cfg_db
def wg_show(cfg, db, name: str):
    """Show details for a specific working group."""
    drafts = db.wg_drafts(name)
    if not drafts:
        console.print(f"[red]No drafts found for WG: {name}[/]")
        return

    console.print(f"\n[bold]Working Group: {name}[/] ({len(drafts)} drafts)\n")

    table = Table()
    table.add_column("Date", style="dim", width=10)
    table.add_column("Name", style="cyan")
    table.add_column("Title", max_width=50)
    table.add_column("Score", justify="right", width=6)

    for d in drafts:
        rating = db.get_rating(d.name)
        score = f"{rating.composite_score:.1f}" if rating else "-"
        table.add_row(d.date, d.name, d.title[:50], score)

    console.print(table)

    # Show ideas for this WG
    ideas = []
    for d in drafts:
        ideas.extend(db.get_ideas_for_draft(d.name))
    if ideas:
        console.print(f"\n[bold]Ideas ({len(ideas)}):[/]")
        for idea in ideas[:15]:
            console.print(f"  - [cyan]{idea['title']}[/]: {idea['description'][:80]}")
        if len(ideas) > 15:
            console.print(f"  [dim]... and {len(ideas) - 15} more[/]")


@wg.command("overlaps")
@click.option("--min-wgs", default=2, help="Minimum WGs sharing a category to show")
@pass_cfg_db
def wg_overlaps(cfg, db, min_wgs: int):
    """Find categories and ideas that span multiple WGs — alignment opportunities."""
    # Category spread across WGs
    spread = db.category_wg_spread()
    multi = [s for s in spread if s["wg_count"] >= min_wgs
             and not all(w["wg"] == "none" for w in s["wgs"])]

    if multi:
        console.print(f"\n[bold]Categories spanning {min_wgs}+ WGs[/]\n")
        for s in multi:
            wg_strs = [f"{w['wg']}({w['count']})" for w in s["wgs"] if w["wg"] != "none"]
            if wg_strs:
                console.print(f"  [cyan]{s['category']}[/] — {s['total_drafts']} drafts across {s['wg_count']} WGs")
                console.print(f"    WGs: {', '.join(wg_strs)}")

    # Idea overlap across WGs
    idea_overlaps = db.wg_idea_overlap()
    cross_wg = [o for o in idea_overlaps
                if not all(w == "none" for w in o["wg_names"])]

    if cross_wg:
        console.print(f"\n[bold]Ideas appearing in {min_wgs}+ WGs ({len(cross_wg)} found)[/]\n")
        for o in cross_wg[:20]:
            real_wgs = [w for w in o["wg_names"] if w != "none"]
            console.print(f"  [cyan]{o['idea_title']}[/] — WGs: {', '.join(real_wgs)}")
            for entry in o["wgs"]:
                if entry["wg"] != "none":
                    console.print(f"    - [{entry['wg']}] {entry['draft_name']}")
        if len(cross_wg) > 20:
            console.print(f"\n  [dim]... and {len(cross_wg) - 20} more[/]")

    if not multi and not cross_wg:
        console.print("[yellow]No cross-WG overlaps found.[/]")


@wg.command("alignment")
@pass_cfg_db
def wg_alignment(cfg, db):
    """Identify where individual drafts should be consolidated into WG standards."""
    # Compare individual vs WG category distribution
    dist = db.individual_vs_wg_categories()
    indiv = dist["individual"]
    adopted = dist["wg_adopted"]

    console.print("\n[bold]Individual vs WG-Adopted Category Distribution[/]\n")

    table = Table()
    table.add_column("Category", width=25)
    table.add_column("Individual", justify="right", width=10)
    table.add_column("WG-Adopted", justify="right", width=10)
    table.add_column("Signal", width=40)

    all_cats = sorted(set(list(indiv.keys()) + list(adopted.keys())))
    for cat in all_cats:
        i_count = indiv.get(cat, 0)
        w_count = adopted.get(cat, 0)
        signal = ""
        if i_count >= 5 and w_count == 0:
            signal = "[yellow]High individual activity, no WG — needs WG?[/]"
        elif i_count >= 3 and w_count >= 1:
            signal = "[green]WG exists, individual drafts could target it[/]"
        elif w_count > i_count and i_count > 0:
            signal = "[dim]WG leading, some individual work[/]"
        table.add_row(cat, str(i_count), str(w_count), signal)

    console.print(table)

    # Find overlap clusters within individual submissions that might warrant a WG
    console.print("\n[bold]Consolidation Candidates[/]")
    console.print("[dim]Categories with many individual drafts but no WG adoption — "
                  "potential for new WG or BoF[/]\n")

    candidates = []
    for cat in all_cats:
        i_count = indiv.get(cat, 0)
        w_count = adopted.get(cat, 0)
        if i_count >= 5 and w_count == 0:
            candidates.append((cat, i_count))

    if candidates:
        for cat, count in sorted(candidates, key=lambda x: x[1], reverse=True):
            console.print(f"  [yellow]{cat}[/]: {count} individual drafts, no WG home")
            # Show sample drafts
            rows = db.conn.execute("""
                SELECT d.name, d.title FROM drafts d
                JOIN ratings r ON d.name = r.draft_name
                WHERE (d."group" = 'none' OR d."group" IS NULL)
                  AND r.categories LIKE ?
                ORDER BY (r.novelty * 0.30 + r.relevance * 0.25 + r.maturity * 0.20
                          + r.momentum * 0.15 + (6 - r.overlap) * 0.10) DESC
                LIMIT 5
            """, (f"%{cat}%",)).fetchall()
            for row in rows:
                console.print(f"    - {row['name']}: {row['title'][:60]}")
            console.print()
    else:
        console.print("  [green]All active categories have WG representation.[/]")


@wg.command("targets")
@pass_cfg_db
def wg_targets(cfg, db):
    """Suggest best WGs for submitting new work in each category."""
    spread = db.category_wg_spread()
    summaries = {s["wg"]: s for s in db.wg_summary()}

    console.print("\n[bold]Recommended Submission Targets by Category[/]\n")

    for s in spread:
        cat = s["category"]
        # Filter to real WGs (not 'none')
        real_wgs = [w for w in s["wgs"] if w["wg"] != "none"]
        if not real_wgs:
            console.print(f"  [cyan]{cat}[/]: [yellow]No active WG — individual submission[/]")
            continue

        best = real_wgs[0]
        wg_info = summaries.get(best["wg"], {})
        console.print(
            f"  [cyan]{cat}[/]: [bold green]{best['wg']}[/] "
            f"({best['count']} drafts"
            f"{', avg relevance ' + str(wg_info.get('avg_relevance', '?')) if wg_info else ''})"
        )
        if len(real_wgs) > 1:
            alts = ", ".join(f"{w['wg']}({w['count']})" for w in real_wgs[1:3])
            console.print(f"    Also: {alts}")

    console.print()


# ── visualize ────────────────────────────────────────────────────────────


@click.group()
def viz():
    """Generate interactive visualizations (HTML/PNG)."""
    pass


@viz.command("all")
@pass_cfg_db
def viz_all(cfg, db):
    """Generate all available visualizations."""
    from ..visualize import Visualizer
    v = Visualizer(cfg, db)
    paths = v.generate_all()
    console.print(f"\n[bold green]{len(paths)} visualizations[/] saved to {v.output_dir}/")


@viz.command("landscape")
@click.option("--method", "-m", default="tsne", type=click.Choice(["umap", "tsne"]),
              help="Dimensionality reduction method")
@pass_cfg_db
def viz_landscape(cfg, db, method: str):
    """2D scatter of draft embeddings colored by category."""
    from ..visualize import Visualizer
    path = Visualizer(cfg, db).landscape_scatter(method=method)
    console.print(f"Saved: [bold]{path}[/]")


@viz.command("heatmap")
@pass_cfg_db
def viz_heatmap(cfg, db):
    """Clustered similarity heatmap (PNG)."""
    from ..visualize import Visualizer
    path = Visualizer(cfg, db).similarity_heatmap()
    console.print(f"Saved: [bold]{path}[/]")


@viz.command("distributions")
@pass_cfg_db
def viz_distributions(cfg, db):
    """Rating dimension distributions by category (PNG)."""
    from ..visualize import Visualizer
    path = Visualizer(cfg, db).score_distributions()
    console.print(f"Saved: [bold]{path}[/]")


@viz.command("timeline")
@pass_cfg_db
def viz_timeline(cfg, db):
    """Stacked area chart of monthly submissions."""
    from ..visualize import Visualizer
    path = Visualizer(cfg, db).timeline_chart()
    console.print(f"Saved: [bold]{path}[/]")


@viz.command("bubble")
@pass_cfg_db
def viz_bubble(cfg, db):
    """Interactive bubble chart: novelty vs maturity."""
    from ..visualize import Visualizer
    path = Visualizer(cfg, db).bubble_explorer()
    console.print(f"Saved: [bold]{path}[/]")


@viz.command("radar")
@pass_cfg_db
def viz_radar(cfg, db):
    """Radar chart of average category rating profiles."""
    from ..visualize import Visualizer
    path = Visualizer(cfg, db).category_radar()
    console.print(f"Saved: [bold]{path}[/]")


@viz.command("network")
@click.option("--min-shared", "-n", default=2, help="Minimum shared drafts for an edge")
@pass_cfg_db
def viz_network(cfg, db, min_shared: int):
    """Interactive author collaboration network graph."""
    from ..visualize import Visualizer
    path = Visualizer(cfg, db).author_network(min_shared=min_shared)
    console.print(f"Saved: [bold]{path}[/]")


@viz.command("treemap")
@pass_cfg_db
def viz_treemap(cfg, db):
    """Category treemap colored by average score."""
    from ..visualize import Visualizer
    path = Visualizer(cfg, db).category_treemap()
    console.print(f"Saved: [bold]{path}[/]")


@viz.command("quality")
@pass_cfg_db
def viz_quality(cfg, db):
    """Score vs uniqueness scatter (quality vs redundancy)."""
    from ..visualize import Visualizer
    path = Visualizer(cfg, db).score_vs_overlap()
    console.print(f"Saved: [bold]{path}[/]")


@viz.command("orgs")
@pass_cfg_db
def viz_orgs(cfg, db):
    """Organization contribution bar chart."""
    from ..visualize import Visualizer
    path = Visualizer(cfg, db).org_contributions()
    console.print(f"Saved: [bold]{path}[/]")


@viz.command("ideas")
@pass_cfg_db
def viz_ideas(cfg, db):
    """Ideas frequency chart by type."""
    from ..visualize import Visualizer
    path = Visualizer(cfg, db).ideas_chart()
    console.print(f"Saved: [bold]{path}[/]")


@viz.command("browser")
@pass_cfg_db
def viz_browser(cfg, db):
    """Interactive filterable draft browser (standalone HTML)."""
    from ..visualize import Visualizer
    path = Visualizer(cfg, db).draft_browser()
    console.print(f"Saved: [bold]{path}[/]")


# ── export ──────────────────────────────────────────────────────────────────


@click.command()
@click.option("--type", "export_type", type=click.Choice(["drafts", "ideas", "gaps", "authors", "ratings"]),
              required=True, help="Type of data to export")
@click.option("--format", "fmt", type=click.Choice(["json", "csv"]), default="json", help="Output format")
@click.option("--output", "-o", "output_file", type=click.Path(), default=None,
              help="Output file (default: stdout)")
def export(export_type: str, fmt: str, output_file: str | None):
    """Export data as JSON or CSV."""
    import csv as csv_mod
    import io
    import json

    cfg = _get_config()
    db = Database(cfg)

    try:
        rows: list[dict] = []

        if export_type == "drafts":
            drafts = db.list_drafts(limit=10000, order_by="name ASC")
            for d in drafts:
                rating = db.get_rating(d.name)
                row = {
                    "name": d.name,
                    "title": d.title,
                    "rev": d.rev,
                    "date": d.date,
                    "pages": d.pages or 0,
                    "group": d.group or "",
                }
                if rating:
                    row["score"] = round(rating.composite_score, 2)
                    row["novelty"] = rating.novelty
                    row["maturity"] = rating.maturity
                    row["overlap"] = rating.overlap
                    row["momentum"] = rating.momentum
                    row["relevance"] = rating.relevance
                    row["categories"] = json.dumps(rating.categories)
                    row["summary"] = rating.summary
                rows.append(row)

        elif export_type == "ideas":
            ideas = db.all_ideas()
            rows = ideas

        elif export_type == "gaps":
            gaps = db.all_gaps()
            rows = gaps

        elif export_type == "authors":
            top = db.top_authors(limit=10000)
            for name, aff, cnt, drafts_list, _pid in top:
                rows.append({
                    "name": name,
                    "affiliation": aff,
                    "draft_count": cnt,
                    "drafts": json.dumps(drafts_list),
                })

        elif export_type == "ratings":
            pairs = db.drafts_with_ratings(limit=10000)
            for draft, rating in pairs:
                rows.append({
                    "name": draft.name,
                    "title": draft.title,
                    "score": round(rating.composite_score, 2),
                    "novelty": rating.novelty,
                    "maturity": rating.maturity,
                    "overlap": rating.overlap,
                    "momentum": rating.momentum,
                    "relevance": rating.relevance,
                    "categories": json.dumps(rating.categories),
                    "summary": rating.summary,
                })

        if fmt == "json":
            text = json.dumps(rows, indent=2, ensure_ascii=False)
        else:
            # CSV
            if not rows:
                text = ""
            else:
                si = io.StringIO()
                writer = csv_mod.DictWriter(si, fieldnames=rows[0].keys())
                writer.writeheader()
                for row in rows:
                    writer.writerow(row)
                text = si.getvalue()

        if output_file:
            Path(output_file).write_text(text, encoding="utf-8")
            console.print(f"Exported [bold green]{len(rows)}[/] {export_type} to [cyan]{output_file}[/] ({fmt})")
        else:
            click.echo(text)

    finally:
        db.close()
