from __future__ import annotations

import argparse
import asyncio
import json
from datetime import timedelta
from pathlib import Path
from typing import Any

from crawlee.crawlers import BeautifulSoupCrawler, BeautifulSoupCrawlingContext


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(description="TIP optional Crawlee Python worker")
    parser.add_argument("--mode", choices=["beautifulsoup"], default="beautifulsoup")
    parser.add_argument("--url", action="append", required=True, help="URL to crawl. Repeatable.")
    parser.add_argument("--out", required=True, help="JSONL output path.")
    parser.add_argument("--max-requests", type=int, default=10)
    parser.add_argument("--timeout-seconds", type=int, default=30)
    parser.add_argument("--label", default="tip-crawlee-python")
    return parser.parse_args()


def write_jsonl(path: Path, record: dict[str, Any]) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    with path.open("a", encoding="utf-8") as handle:
        handle.write(json.dumps(record, ensure_ascii=False, sort_keys=True) + "\n")


async def run_beautifulsoup(args: argparse.Namespace) -> None:
    out = Path(args.out)
    if out.exists():
        out.unlink()

    crawler = BeautifulSoupCrawler(
        max_request_retries=1,
        request_handler_timeout=timedelta(seconds=args.timeout_seconds),
        max_requests_per_crawl=args.max_requests,
    )

    @crawler.router.default_handler
    async def request_handler(context: BeautifulSoupCrawlingContext) -> None:
        title = context.soup.title.string.strip() if context.soup.title and context.soup.title.string else None
        headings = [
            heading.get_text(" ", strip=True)
            for heading in context.soup.find_all(["h1", "h2", "h3"])
        ][:25]
        images = [
            img.get("src")
            for img in context.soup.find_all("img")
            if img.get("src")
        ][:25]
        links = [
            link.get("href")
            for link in context.soup.find_all("a")
            if link.get("href")
        ][:100]
        write_jsonl(
            out,
            {
                "kind": "tip_crawlee_python_page",
                "label": args.label,
                "url": context.request.url,
                "title": title,
                "headings": headings,
                "image_candidates": images,
                "link_candidates": links,
            },
        )

    await crawler.run(args.url)


async def async_main() -> None:
    args = parse_args()
    if args.mode == "beautifulsoup":
        await run_beautifulsoup(args)


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


if __name__ == "__main__":
    main()
