#!/usr/bin/env python3
"""
Fetch a platform's related-search / autocomplete suggestions for one or more
keywords, and store them locally keyed by the source keyword.

Platform-specific details (which endpoint, which params, how to parse the
response) live in search_suggestion_providers/ -- this file only handles the
CLI, resuming, and storage, and knows nothing about any specific backend.

Usage:
  python search_suggestions.py --platform youtube declutter minimalism
  python search_suggestions.py --platform tiktok --file keywords.txt
  python search_suggestions.py --platform youtube --file declutter_keyword_clusters.csv --column keyword
  python search_suggestions.py --platform youtube --language ja --region JP tidying
"""

import argparse
import csv
import json
import os
import time
from datetime import datetime, timezone

from search_suggestion_providers import PLATFORMS
from search_suggestion_providers._http import REQUEST_DELAY_SECONDS


def build_arg_parser():
    pre_parser = argparse.ArgumentParser(add_help=False)
    pre_parser.add_argument("--platform", required=True, choices=sorted(PLATFORMS))
    pre_args, _ = pre_parser.parse_known_args()

    provider = PLATFORMS[pre_args.platform]

    parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument("--platform", required=True, choices=sorted(PLATFORMS))
    parser.add_argument("keywords", nargs="*", help="Keywords to fetch suggestions for")
    parser.add_argument("--file", help="Path to a .txt (one keyword per line) or .csv file of keywords")
    parser.add_argument("--column", help="Column name holding keywords, required when --file is a .csv")
    parser.add_argument("--force", action="store_true", help="Re-fetch keywords already present in the output file")
    for name, default in provider.EXTRA_PARAM_DEFAULTS.items():
        parser.add_argument(f"--{name}", default=default, help=f"Passed through to the {pre_args.platform} provider (default: {default})")

    return parser


def load_keywords_from_file(path, column):
    if path.endswith(".csv"):
        if not column:
            raise SystemExit("❌ --column is required when --file is a .csv")
        with open(path, newline="", encoding="utf-8") as f:
            rows = list(csv.DictReader(f))
        return [row[column].strip() for row in rows if row.get(column, "").strip()]

    with open(path, encoding="utf-8") as f:
        return [line.strip() for line in f if line.strip()]


def collect_keywords(args):
    keywords = list(args.keywords)
    if args.file:
        keywords += load_keywords_from_file(args.file, args.column)

    seen = set()
    deduped = []
    for kw in keywords:
        if kw not in seen:
            seen.add(kw)
            deduped.append(kw)

    if not deduped:
        raise SystemExit("❌ No keywords given -- pass keywords as positional args and/or --file")

    return deduped


def load_existing(output_path):
    if os.path.exists(output_path):
        with open(output_path, encoding="utf-8") as f:
            return json.load(f)
    return {}


def save(output_path, data):
    with open(output_path, "w", encoding="utf-8") as f:
        json.dump(data, f, indent=2, ensure_ascii=False)


def extra_params_from_args(args, provider):
    return {name: getattr(args, name) for name in provider.EXTRA_PARAM_DEFAULTS}


def main():
    args = build_arg_parser().parse_args()
    provider = PLATFORMS[args.platform]
    keywords = collect_keywords(args)
    extra_params = extra_params_from_args(args, provider)

    output_path = f"{args.platform}_search_suggestions.json"
    data = load_existing(output_path)

    print(f"🔍 Fetching {args.platform} search suggestions for {len(keywords)} keyword(s)...")
    for i, keyword in enumerate(keywords, 1):
        if keyword in data and not args.force:
            print(f"  [{i}/{len(keywords)}] ⏭️  skip (already fetched): {keyword}")
            continue

        print(f"  [{i}/{len(keywords)}] fetching: {keyword}")
        result = provider.fetch(keyword, **extra_params)
        if result is None:
            print(f"  ⚠️ giving up on '{keyword}' after retries -- will retry on next run")
            time.sleep(REQUEST_DELAY_SECONDS)
            continue

        data[keyword] = {
            "platform": args.platform,
            "suggestions": result["suggestions"],
            "params": extra_params,
            "fetched_at": datetime.now(timezone.utc).isoformat(),
            "raw_response": result["raw_response"],
        }
        save(output_path, data)
        print(f"    ✅ {len(result['suggestions'])} suggestions")
        time.sleep(REQUEST_DELAY_SECONDS)

    print(f"✅ Done. {output_path} has {len(data)} keyword(s).")


if __name__ == "__main__":
    main()
