"""CLI script to regenerate the bundled chain registry snapshot.

Usage::

    python -m blockparty.registry.generate

Fetches chain data from Etherscan, Routescan (mainnet + testnet), and
Blockscout APIs, merges the results, probes Routescan vanity hostnames,
and writes:
  - ``src/blockparty/registry/data/chains.json``
  - ``SUPPORTED_CHAINS.md``
"""

from __future__ import annotations

import asyncio
import json
from pathlib import Path

import aiohttp

from blockparty.registry.sources import (
    fetch_blockscout_chains,
    fetch_etherscan_chains,
    fetch_routescan_chains,
    fetch_routescan_vanity_urls,
    merge_chain_entries,
)

DATA_DIR = Path(__file__).parent / "data"
CHAINS_JSON = DATA_DIR / "chains.json"

# Find project root (for SUPPORTED_CHAINS.md) — walk up from this file.
_PROJECT_ROOT = Path(__file__).resolve().parents[3]  # src/blockparty/registry → project root


async def _generate() -> None:
    headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_10)"}
    async with aiohttp.ClientSession(headers=headers) as session:
        # ------------------------------------------------------------------
        # 1. Fetch from all sources
        # ------------------------------------------------------------------
        print("Fetching chain data...")

        try:
            etherscan = await fetch_etherscan_chains(session)
            print(f"  ✓ Fetched {len(etherscan)} chains from Etherscan")
        except Exception as exc:
            print(f"  ✗ Etherscan failed: {exc}")
            etherscan = []

        try:
            routescan_main = await fetch_routescan_chains(session, network="mainnet")
            print(f"  ✓ Fetched {len(routescan_main)} chains from Routescan (mainnet)")
        except Exception as exc:
            print(f"  ✗ Routescan (mainnet) failed: {exc}")
            routescan_main = []

        try:
            routescan_test = await fetch_routescan_chains(session, network="testnet")
            print(f"  ✓ Fetched {len(routescan_test)} chains from Routescan (testnet)")
        except Exception as exc:
            print(f"  ✗ Routescan (testnet) failed: {exc}")
            routescan_test = []

        try:
            blockscout = await fetch_blockscout_chains(session)
            print(f"  ✓ Fetched {len(blockscout)} chains from Blockscout")
        except Exception as exc:
            print(f"  ✗ Blockscout failed: {exc}")
            blockscout = []

        # ------------------------------------------------------------------
        # 2. Merge
        # ------------------------------------------------------------------
        merged = merge_chain_entries(
            [
                etherscan,
                routescan_main,
                routescan_test,
                blockscout,
            ]
        )
        print(f"  ✓ Merged: {len(merged)} unique chains")

        # ------------------------------------------------------------------
        # 3. Fetch Routescan vanity hostnames
        # ------------------------------------------------------------------
        try:
            vanity_map = await fetch_routescan_vanity_urls(session)
            print(f"  ✓ Fetched {len(vanity_map)} Routescan vanity hostnames")

            # Apply vanity URLs to merged entries.
            applied = 0
            for entry in merged:
                vanity_url = vanity_map.get(entry.chain_id)
                if vanity_url:
                    for exp in entry.explorers:
                        if exp.type == "routescan":
                            exp.frontend_url_vanity = vanity_url
                            applied += 1

            print(f"  ✓ Applied vanity hostnames to {applied} explorers")
        except Exception as exc:
            print(f"  ✗ Routescan vanity URL fetch failed: {exc}")

        # ------------------------------------------------------------------
        # 4. Write chains.json
        # ------------------------------------------------------------------
        DATA_DIR.mkdir(parents=True, exist_ok=True)
        serialized = [entry.model_dump(mode="json") for entry in sorted(merged, key=lambda e: e.chain_id)]
        CHAINS_JSON.write_text(
            json.dumps(serialized, indent=2, ensure_ascii=False) + "\n",
            encoding="utf-8",
        )
        print(f"  ✓ Written to {CHAINS_JSON}")

        # ------------------------------------------------------------------
        # 5. Write SUPPORTED_CHAINS.md
        # ------------------------------------------------------------------
        md_path = _PROJECT_ROOT / "SUPPORTED_CHAINS.md"
        lines = [
            "# Supported Chains",
            "",
            "Auto-generated by `python -m blockparty.registry.generate`.",
            "",
            "| Chain ID | Name | Testnet | Etherscan | Routescan | Blockscout |",
            "|----------|------|---------|-----------|-----------|------------|",
        ]
        for entry in sorted(merged, key=lambda e: e.chain_id):
            types = {e.type for e in entry.explorers}
            lines.append(
                f"| {entry.chain_id} | {entry.name} | "
                f"{'✓' if entry.is_testnet else ''} | "
                f"{'✓' if 'etherscan' in types else ''} | "
                f"{'✓' if 'routescan' in types else ''} | "
                f"{'✓' if 'blockscout' in types else ''} |"
            )
        lines.append("")
        md_path.write_text("\n".join(lines), encoding="utf-8")
        print(f"  ✓ Written to {md_path}")


def main() -> None:
    asyncio.run(_generate())


if __name__ == "__main__":
    main()
