"""CLI entry point: platoon feed, platoon search, platoon export."""

from __future__ import annotations

import argparse
import json
import subprocess
import sys
from datetime import datetime
from pathlib import Path

from platoon.config import load_config, resolve_profile
from platoon.fetcher import Fetcher
from platoon.images import enrich_images
from platoon.models import Item
from platoon.renderer import render_html, render_json, save_output
from platoon.scorer import score_and_sort
from platoon.sources import SOURCE_FETCHERS


def _fetch_and_score(config: dict, source_filter: set | None, fetcher: Fetcher,
                     tavily_key: str | None = None) -> list[Item]:
    """Fetch feeds, enrich with web search, score, and backfill sparse categories."""
    from platoon.config import INTEREST_FALLBACKS
    from platoon.sources.google_news import fetch_google_news
    from platoon.sources.web_search import web_search_enrich
    import random

    all_items: list[Item] = []
    sources_cfg = config.get("sources", {})

    # --- Phase 1: Fetch from configured feed sources ---
    for source_name, source_cfg in sources_cfg.items():
        if source_filter and source_name not in source_filter:
            continue
        if not source_cfg.get("enabled", True):
            continue
        fetch_fn = SOURCE_FETCHERS.get(source_name)
        if not fetch_fn:
            print(f"No fetcher for source: {source_name}", file=sys.stderr)
            continue
        try:
            items = fetch_fn(source_cfg, fetcher)
            all_items.extend(items)
        except Exception as e:
            print(f"Error fetching {source_name}: {e}", file=sys.stderr)

    print(f"  Feeds: {len(all_items)} raw items")

    # --- Phase 2: Tavily web search (if key available) ---
    # Searches each category for NEW content not already in feeds
    if tavily_key:
        existing_urls = {item.url for item in all_items}
        categories = config.get("categories", {})
        interests = config.get("interests", [])
        web_items = web_search_enrich(
            categories=categories,
            interests=interests,
            existing_urls=existing_urls,
            api_key=tavily_key,
            max_per_category=3,
            time_range="week",
        )
        print(f"  Web search: {len(web_items)} new items from unique sources")
        all_items.extend(web_items)

    # --- Phase 3: Score everything together ---
    scored = score_and_sort(all_items, config)

    # --- Phase 4: Backfill sparse categories via Google News ---
    categories = config.get("categories", {})
    min_per_cat = 2
    cat_counts: dict[str, int] = {}
    for item in scored:
        cat_counts[item.category] = cat_counts.get(item.category, 0) + 1

    sparse = [cat for cat in categories if cat_counts.get(cat, 0) < min_per_cat]
    if sparse:
        print(f"  Backfilling sparse categories: {sparse}")
        for cat in sparse:
            queries = INTEREST_FALLBACKS.get(cat, [])
            if not queries:
                continue
            query = random.choice(queries)
            try:
                fallback_cfg = {"queries": [query], "max_items_per_query": 4}
                extra = fetch_google_news(fallback_cfg, fetcher)
                all_items.extend(extra)
            except Exception as e:
                print(f"  Fallback error for {cat}: {e}", file=sys.stderr)

        scored = score_and_sort(all_items, config)

    print(f"  Final: {len(scored)} items")
    return scored


def run_feed(args):
    """Fetch, score, and render the feed for one or all profiles."""
    from platoon.config import resolve_keys
    config = load_config(args.config)
    source_filter = set(args.sources) if args.sources else None

    # Tavily key: CLI flag > P8_TAVILY_KEY > P8_PLATOON_KEYS > TAVILY_API_KEY
    keys = resolve_keys()
    tavily_key = getattr(args, "tavily_key", None) or keys.get("tavily", "")
    if tavily_key:
        print(f"  Tavily web search: enabled")

    # Determine which profiles to run
    profiles = config.get("profiles", {})
    if args.profile:
        profile_names = [args.profile]
    else:
        profile_names = list(profiles.keys())

    fetcher = Fetcher(config.get("fetcher", {}))
    all_paths = []

    for pname in profile_names:
        print(f"\n{'='*50}")
        print(f"  Profile: {pname}")
        print(f"{'='*50}")

        pcfg = resolve_profile(config, pname)
        scored = _fetch_and_score(pcfg, source_filter, fetcher, tavily_key=tavily_key)

        # Enrich images (og:image scrape + category fallbacks)
        enrich_images(scored, fetcher)

        if args.dry_run:
            _print_dry_run(scored)
            continue

        fmt = args.output or pcfg.get("output", {}).get("format", "html")
        if fmt == "json":
            content = render_json(scored)
        else:
            content = render_html(scored, pcfg)

        path = save_output(content, fmt, pcfg, suffix=pname)
        all_paths.append(path)

    fetcher.close()

    if args.open and all_paths:
        for p in all_paths:
            _open_file(p)


def _print_dry_run(items: list[Item]):
    """Print scored items to stdout."""
    current_cat = None
    for item in items:
        if item.category != current_cat:
            current_cat = item.category
            print(f"\n  --- {current_cat} ---")
        eng_parts = []
        for k, v in item.engagement.items():
            if isinstance(v, (int, float)) and v > 0:
                eng_parts.append(f"{k}={v}")
        eng_str = f"  [{', '.join(eng_parts)}]" if eng_parts else ""
        print(f"  [{item.score:.2f}] {item.title}")
        print(f"    {item.source} {eng_str}")
        if item.tags:
            print(f"    tags: {', '.join(item.tags[:5])}")


def run_export(args):
    """Run feed pipeline and export YAML (percolate entities) + HTML viewer."""
    from uuid import UUID

    import yaml

    from platoon.config import resolve_keys
    from platoon.providers import FeedProvider

    config = load_config(args.config)
    keys = resolve_keys()
    tavily_key = getattr(args, "tavily_key", None) or keys.get("tavily", "")

    user_id = UUID(args.user_id) if args.user_id else None

    profiles = config.get("profiles", {})
    if args.profile:
        profile_names = [args.profile]
    else:
        profile_names = list(profiles.keys())

    provider = FeedProvider(tavily_key=tavily_key or None)

    for pname in profile_names:
        print(f"\n{'='*50}")
        print(f"  Export: {pname}")
        print(f"{'='*50}")

        pcfg = resolve_profile(config, pname)
        result = provider.run(pcfg, user_id=user_id)

        print(f"  Resources: {len(result.resources)}")
        print(f"  Moments:   {len(result.moments)}")

        out_dir = Path(args.output_dir)
        out_dir.mkdir(parents=True, exist_ok=True)

        # YAML exports (percolate entities)
        export = result.to_export_dicts()
        res_path = out_dir / f"resources-{pname}.yaml"
        mom_path = out_dir / f"moments-{pname}.yaml"
        res_path.write_text(yaml.dump(export["resources"], default_flow_style=False, allow_unicode=True))
        mom_path.write_text(yaml.dump(export["moments"], default_flow_style=False, allow_unicode=True))
        print(f"  Written: {res_path}")
        print(f"  Written: {mom_path}")

        # HTML viewer
        date_str = datetime.now().strftime("%Y-%m-%d")
        html_path = out_dir / f"{date_str}-{pname}.html"
        html_content = render_html(result.items, pcfg)
        html_path.write_text(html_content)
        print(f"  Written: {html_path}")


def _open_file(path: Path):
    """Open file in default browser."""
    import platform
    system = platform.system()
    try:
        if system == "Darwin":
            subprocess.run(["open", str(path)])
        elif system == "Linux":
            subprocess.run(["xdg-open", str(path)])
        elif system == "Windows":
            subprocess.run(["start", str(path)], shell=True)
    except Exception as e:
        print(f"Could not open browser: {e}", file=sys.stderr)


def main():
    parser = argparse.ArgumentParser(
        prog="platoon",
        description="News feed digest with HTML card viewer",
    )
    subparsers = parser.add_subparsers(dest="command")

    # feed subcommand
    feed_parser = subparsers.add_parser("feed", help="Fetch and render news feed")
    feed_parser.add_argument("--config", default=None, help="Path to config YAML")
    feed_parser.add_argument("--profile", default=None, help="Profile name (default: run all)")
    feed_parser.add_argument("--dry-run", action="store_true", help="Fetch + score, print to stdout")
    feed_parser.add_argument("--sources", nargs="+", help="Subset of sources to fetch")
    feed_parser.add_argument("--output", choices=["html", "json"], help="Output format")
    feed_parser.add_argument("--open", action="store_true", help="Open HTML in browser")
    feed_parser.add_argument("--tavily-key", default=None, dest="tavily_key",
                             help="Tavily API key for web search enrichment (or set TAVILY_API_KEY)")

    # search subcommand
    search_parser = subparsers.add_parser("search", help="Tavily web search")
    search_parser.add_argument("query", help="Search query")
    search_parser.add_argument("--max-results", type=int, default=5, help="Max results")
    search_parser.add_argument("--topic", default="news", help="Topic: news, general")
    search_parser.add_argument("--time-range", default=None, help="Time range: day, week, month")
    search_parser.add_argument("--api-key", default=None, help="Tavily API key (or set TAVILY_API_KEY)")

    # export subcommand
    export_parser = subparsers.add_parser("export", help="Export feed as percolate Resources + Moments")
    export_parser.add_argument("--config", default=None, help="Path to config YAML")
    export_parser.add_argument("--profile", default=None, help="Profile name (default: run all)")
    export_parser.add_argument("--output-dir", default="./export", dest="output_dir",
                               help="Output directory (default: ./export)")
    export_parser.add_argument("--user-id", default=None, dest="user_id",
                               help="User UUID for resource ownership")
    export_parser.add_argument("--tavily-key", default=None, dest="tavily_key",
                               help="Tavily API key for web search enrichment")

    # forecast and optimize subcommands
    from platoon.learning.cli import add_forecast_parser, add_optimize_parser, add_recommend_parser
    add_forecast_parser(subparsers)
    add_optimize_parser(subparsers)
    add_recommend_parser(subparsers)

    # MCP server
    subparsers.add_parser("mcp", help="Run MCP server over stdio (for Claude Code)")


    args = parser.parse_args()

    if args.command == "feed":
        run_feed(args)
    elif args.command == "search":
        from platoon.tavily_search import main_search
        main_search(args)
    elif args.command == "export":
        run_export(args)
    elif args.command == "forecast":
        from platoon.learning.cli import run_forecast
        run_forecast(args)
    elif args.command == "optimize":
        from platoon.learning.cli import run_optimize
        run_optimize(args)
    elif args.command == "recommend":
        from platoon.learning.cli import run_recommend
        run_recommend(args)
    elif args.command == "mcp":
        import asyncio
        from platoon.mcp.server import create_mcp_server
        mcp = create_mcp_server()
        asyncio.run(mcp.run_async(transport="stdio"))
    else:
        parser.print_help()


if __name__ == "__main__":
    main()
