"""Apify command registration (discover)."""

from __future__ import annotations

import json
import sys
import time
from pathlib import Path
from typing import Optional

import click

from g_gremlin import errors as error_helpers
from g_gremlin.safety import SafetyContext
from g_gremlin.cli import apify


@apify.command("discover")
@click.option(
    "--csv",
    "csv_path",
    required=True,
    type=click.Path(exists=True, dir_okay=False, path_type=Path),
    help="Input CSV with company and title columns.",
)
@click.option(
    "--company-col",
    "company_col",
    default="company",
    help="Column containing company names (default: company).",
)
@click.option(
    "--title-col",
    "title_col",
    default="title",
    help="Column containing job titles (default: title).",
)
@click.option(
    "--output",
    "output_path",
    required=True,
    type=click.Path(dir_okay=False, path_type=Path),
    help="Output CSV path for discovered people.",
)
@click.option(
    "--limit",
    default=0,
    type=int,
    help="Limit rows to process (0 = all).",
)
@click.option(
    "--actor",
    "actor_id",
    default=None,
    help="Apify actor ID for people search (default: harvestapi/linkedin-profile-search, FREE).",
)
@click.option(
    "--concurrency",
    default=5,
    type=int,
    help="Number of concurrent searches (default: 5, max: 15). Higher = faster but may hit rate limits.",
)
@click.option(
    "--dry-run",
    is_flag=True,
    help="Show what would be processed without calling API.",
)
@click.option(
    "--two-step / --no-two-step",
    "two_step",
    default=True,
    help="Use 2-step pipeline: resolve company LinkedIn URL first for better precision (default: on).",
)
@click.option(
    "--json-summary",
    "json_summary",
    is_flag=True,
    help="Emit AgenticResult-style JSON summary.",
)
def apify_discover(
    csv_path: Path,
    company_col: str,
    title_col: str,
    output_path: Path,
    limit: int,
    actor_id: Optional[str],
    concurrency: int,
    dry_run: bool,
    two_step: bool,
    json_summary: bool,
) -> None:
    """
    Discover people by company + title using LinkedIn search via Apify.

    Takes a CSV with company and title columns (e.g., from a tradeshow list)
    and finds actual people names and LinkedIn profiles.

    Example:
        g-gremlin apify discover --csv blind_list.csv --company-col "Company" \
            --title-col "Title" --output enriched.csv
    """
    import csv as csv_module

    from g_gremlin.apify import (
        DEFAULT_PEOPLE_FINDER_ACTOR,
    )

    effective_actor = actor_id or DEFAULT_PEOPLE_FINDER_ACTOR

    # Read input
    with csv_path.open(newline="", encoding="utf-8-sig") as f:
        rows = list(csv_module.DictReader(f))

    if not rows:
        click.echo("Error: No rows found in input file.")
        sys.exit(1)

    headers = list(rows[0].keys())
    if company_col not in headers:
        error = error_helpers.column_not_found_error(
            company_col, headers, context="input CSV"
        )
        click.echo(str(error), err=True)
        sys.exit(1)

    if title_col not in headers:
        error = error_helpers.column_not_found_error(
            title_col, headers, context="input CSV"
        )
        click.echo(str(error), err=True)
        sys.exit(1)

    if limit > 0:
        rows = rows[:limit]

    # Estimate cost based on actor type and pipeline mode
    # HarvestAPI: $0.10/page in Short mode (we use takePages=1, so $0.10/search)
    # Company enrichment: ~$0.025/company (apioracle ~$0.019 + domain->linkedin fallback ~$0.006)
    if "harvestapi" in effective_actor.lower():
        people_cost = len(rows) * 0.10  # $0.10 per search page (Short mode)
        people_note = f"{len(rows)} searches @ $0.10/ea"
    else:
        people_cost = len(rows) * 0.05
        people_note = f"{len(rows)} searches @ $0.05/ea"

    unique_companies = len(set(row.get(company_col, "").strip().lower() for row in rows if row.get(company_col, "").strip()))
    if two_step:
        # ~$0.019 per company lookup + potential domain->linkedin fallback (~$0.006)
        company_cost = unique_companies * 0.025  # Conservative estimate
        total_cost = people_cost + company_cost
        cost_note = f"~${total_cost:.2f} ({people_note} + {unique_companies} company lookups @ ~$0.025 ea)"
    else:
        total_cost = people_cost
        cost_note = f"~${total_cost:.2f} ({people_note})"

    click.echo(f"Loaded {len(rows)} rows from {csv_path}")
    click.echo(f"Actor: {effective_actor}")
    click.echo(f"Pipeline: {'2-step (company URL -> people search)' if two_step else 'direct search'}")
    if two_step:
        click.echo(f"Unique companies: {unique_companies}")
    click.echo(f"Estimated cost: {cost_note}")

    if dry_run:
        click.echo("\n[DRY RUN] Would search for:")
        for idx, row in enumerate(rows[:10]):
            company = row.get(company_col, "").strip()
            title = row.get(title_col, "").strip()
            query = f"{title} at {company}" if title and company else company or title
            click.echo(f"  [{idx + 1}] {query[:60]}")
        if len(rows) > 10:
            click.echo(f"  ... and {len(rows) - 10} more")
        if json_summary:
            safety_ctx = SafetyContext(command="g-gremlin apify discover", remote_mutation=False)
            agentic = safety_ctx.build_result(
                status="success",
                dry_run=True,
                result={
                    "rows_planned": len(rows),
                    "company_col": company_col,
                    "title_col": title_col,
                    "actor": effective_actor,
                    "output": str(output_path),
                },
            )
            click.echo(json.dumps(agentic.to_dict(), indent=2))
        return

    # Discover people using async batch processing
    import asyncio
    from g_gremlin.apify import discover_people_async, discover_people_two_step_async

    # Cap concurrency at 15 (user has 32 concurrent runs, leave headroom for company lookups)
    effective_concurrency = min(max(concurrency, 1), 15)
    click.echo(f"Concurrency: {effective_concurrency} parallel searches")

    start_time = time.time()

    # Run async discovery
    if two_step:
        click.echo(f"\nPhase 1: Resolving {unique_companies} company LinkedIn URLs...")
        click.echo(f"Phase 2: Searching for {len(rows)} people...")

        async def run_discovery():
            return await discover_people_two_step_async(
                rows=rows,
                company_key=company_col,
                title_key=title_col,
                actor_id=effective_actor,
                max_results_per_row=1,
                concurrency=effective_concurrency,
                use_cache=True,
                resolve_company_url=True,
            )
    else:
        click.echo(f"\nSearching for {len(rows)} people...")

        async def run_discovery():
            return await discover_people_async(
                rows=rows,
                company_key=company_col,
                title_key=title_col,
                actor_id=effective_actor,
                max_results_per_row=1,
                concurrency=effective_concurrency,
            )

    raw_results = asyncio.run(run_discovery())

    # Process results and build output
    results = []
    success_count = 0
    cache_hits = 0
    two_step_count = 0

    for raw in raw_results:
        idx = raw.get("idx", 0)
        company = raw.get("company", "")
        title_val = raw.get("title", "")
        full_name = raw.get("full_name", "")
        linkedin_url = raw.get("linkedin_url", "")
        error = raw.get("error")
        pipeline_used = raw.get("pipeline_used", "direct")
        company_linkedin_url = raw.get("company_linkedin_url", "")
        cache_hit = raw.get("cache_hit", False)

        # Quality filter: require LinkedIn profile URL for valid result
        is_valid = bool(full_name and linkedin_url and "linkedin.com/in/" in linkedin_url)

        result = {
            "source_row_idx": idx,
            "input_company": raw.get("input", {}).get(company_col, company),
            "input_title": raw.get("input", {}).get(title_col, title_val),
            "first_name": raw.get("first_name", ""),
            "last_name": raw.get("last_name", ""),
            "full_name": full_name,
            "discovered_title": title_val,
            "discovered_company": company,
            "linkedin_url": linkedin_url,
            "location": raw.get("location", ""),
            "headline": raw.get("headline", ""),
            "confidence": raw.get("confidence", 0.0),
            "pipeline_used": pipeline_used,
            "company_linkedin_url": company_linkedin_url,
            "cache_hit": cache_hit,
            "error": error or "",
        }
        results.append(result)

        if cache_hit:
            cache_hits += 1
        if pipeline_used in ("two_step", "direct_fallback"):
            two_step_count += 1

        if is_valid:
            success_count += 1
            pipeline_tag = "[2S]" if pipeline_used in ("two_step", "direct_fallback") else "[D]"
            cache_tag = " (cached)" if cache_hit else ""
            click.echo(f"[{idx + 1}] {pipeline_tag} {full_name} | {linkedin_url[:50]}{cache_tag}")
        elif error:
            click.echo(f"[{idx + 1}] (error: {error[:40]})")

    # Write output
    output_path.parent.mkdir(parents=True, exist_ok=True)
    fieldnames = list(results[0].keys()) if results else []
    with output_path.open("w", newline="", encoding="utf-8") as f:
        writer = csv_module.DictWriter(f, fieldnames=fieldnames)
        writer.writeheader()
        writer.writerows(results)

    elapsed_total = time.time() - start_time
    click.echo(f"\nDone! {success_count}/{len(results)} discovered in {elapsed_total:.1f}s")
    if two_step:
        click.echo(f"Pipeline: {two_step_count} via 2-step, {len(results) - two_step_count} direct")
    if cache_hits > 0:
        click.echo(f"Cache hits: {cache_hits} (saved {cache_hits} API calls)")
    click.echo(f"Output: {output_path}")

    if json_summary:
        safety_ctx = SafetyContext(command="g-gremlin apify discover", remote_mutation=False)
        agentic = safety_ctx.build_result(
            status="success",
            dry_run=False,
            result={
                "rows_processed": len(results),
                "success_count": success_count,
                "two_step_count": two_step_count,
                "cache_hits": cache_hits,
                "elapsed_seconds": round(elapsed_total, 1),
                "output": str(output_path),
                "actor": effective_actor,
                "pipeline_mode": "two_step" if two_step else "direct",
            },
        )
        click.echo(json.dumps(agentic.to_dict(), indent=2))
