"""Orchestrates all pingers for a site."""

from __future__ import annotations

import sys
from concurrent.futures import ThreadPoolExecutor, as_completed
from dataclasses import dataclass, field
from typing import Callable

from ping_rss.config import Config, SiteConfig
from ping_rss.pingers import gsc, indexnow, pubsubhubbub, xmlrpc_ping

ALL_SERVICES = {"xmlrpc", "pubsub", "indexnow", "gsc"}


@dataclass
class RunResult:
    site: str
    xmlrpc_results: list[xmlrpc_ping.PingResult] = field(default_factory=list)
    pubsub_results: list[pubsubhubbub.PubSubResult] = field(default_factory=list)
    indexnow_result: indexnow.IndexNowResult | None = None
    gsc_result: gsc.GSCBatchResult | None = None
    errors: list[str] = field(default_factory=list)

    @property
    def all_ok(self) -> bool:
        ok = True
        if self.xmlrpc_results:
            ok = ok and all(r.success for r in self.xmlrpc_results)
        if self.pubsub_results:
            ok = ok and all(r.success for r in self.pubsub_results)
        if self.indexnow_result:
            ok = ok and self.indexnow_result.success
        if self.gsc_result:
            ok = ok and all(r.success for r in self.gsc_result.results)
        return ok and not self.errors


def run(
    config: Config,
    site: SiteConfig,
    only: set[str] | None = None,
    urls: list[str] | None = None,
    dry_run: bool = False,
) -> RunResult:
    """Run all (or selected) pingers for a site."""
    services = only or ALL_SERVICES
    result = RunResult(site=site.slug)

    if dry_run:
        _dry_run(site, services, urls)
        return result

    tasks: dict[str, Callable] = {}

    if "xmlrpc" in services:
        tasks["xmlrpc"] = lambda: xmlrpc_ping.ping_all(site)

    if "pubsub" in services:
        tasks["pubsub"] = lambda: pubsubhubbub.publish(site)

    if "indexnow" in services:
        tasks["indexnow"] = lambda: indexnow.submit(site, urls)

    if "gsc" in services and urls:
        tasks["gsc"] = lambda: gsc.inspect_urls(site, config.google, urls)

    with ThreadPoolExecutor(max_workers=len(tasks) or 1) as executor:
        futures = {executor.submit(fn): name for name, fn in tasks.items()}
        for future in as_completed(futures):
            name = futures[future]
            try:
                res = future.result()
                if name == "xmlrpc":
                    result.xmlrpc_results = res
                elif name == "pubsub":
                    result.pubsub_results = res
                elif name == "indexnow":
                    result.indexnow_result = res
                elif name == "gsc":
                    result.gsc_result = res
            except Exception as e:
                result.errors.append(f"{name}: {e}")

    return result


def _dry_run(site: SiteConfig, services: set[str], urls: list[str] | None) -> None:
    """Print what would be done without executing."""
    print(f"\n[DRY RUN] Site: {site.name} ({site.slug})")
    print(f"  Feed URL: {site.feed_url}")
    print(f"  Site URL: {site.site_url}")

    if "xmlrpc" in services:
        print(f"\n  XML-RPC ping ({len(site.ping_services)} services):")
        for svc in site.ping_services:
            print(f"    -> {svc}")

    if "pubsub" in services:
        print(f"\n  WebSub push ({len(site.pubsubhubbub_hubs)} hubs):")
        for hub in site.pubsubhubbub_hubs:
            print(f"    -> {hub}")

    if "indexnow" in services:
        if site.indexnow_key:
            print(f"\n  IndexNow submit:")
            print(f"    -> {site.indexnow_endpoint}")
            print(f"    Key: {site.indexnow_key[:8]}...")
        else:
            print(f"\n  IndexNow: SKIPPED (no key configured)")

    if "gsc" in services:
        if urls:
            print(f"\n  GSC URL Inspection ({len(urls)} URLs):")
            for u in urls[:5]:
                print(f"    -> {u}")
            if len(urls) > 5:
                print(f"    ... and {len(urls) - 5} more")
        else:
            print(f"\n  GSC URL Inspection: SKIPPED (no --urls provided)")

    if urls:
        print(f"\n  URLs to submit:")
        for u in urls:
            print(f"    {u}")

    print()


def print_results(result: RunResult, verbose: bool = False) -> None:
    """Print run results to stdout."""
    print(f"\n{'='*60}")
    print(f"Results for: {result.site}")
    print(f"{'='*60}")

    if result.xmlrpc_results:
        print(f"\nXML-RPC Ping:")
        for r in result.xmlrpc_results:
            if r.rate_limited:
                icon = "~"
            elif r.success:
                icon = "+"
            else:
                icon = "x"
            print(f"  [{icon}] {r.service}")
            if verbose or not r.success or r.rate_limited:
                label = "  RATE LIMITED: " if r.rate_limited else "      "
                print(f"    {label}{r.message}")

    if result.pubsub_results:
        print(f"\nWebSub Push:")
        for r in result.pubsub_results:
            icon = "+" if r.success else "x"
            print(f"  [{icon}] {r.hub}")
            if verbose or not r.success:
                print(f"      {r.message}")

    if result.indexnow_result:
        r = result.indexnow_result
        icon = "+" if r.success else "x"
        print(f"\nIndexNow: [{icon}] {r.message}")
        if r.success:
            print(f"  URLs submitted: {r.urls_submitted}")
        if r.retry_after:
            print(f"  RATE LIMITED: retry after {r.retry_after}s")

    if result.gsc_result:
        print(f"\nGSC URL Inspection:")
        if result.gsc_result.quota_warning:
            print(f"  WARNING: {result.gsc_result.quota_warning}")
        for r in result.gsc_result.results:
            icon = "+" if r.success else "x"
            print(f"  [{icon}] {r.url}")
            if verbose or not r.success:
                print(f"      {r.message}")

    if result.errors:
        print(f"\nErrors:")
        for e in result.errors:
            print(f"  [!] {e}")

    status = "OK" if result.all_ok else "SOME FAILURES"
    print(f"\nStatus: {status}")
    print()
