"""CLI entry point: python -m broken_link_finder"""

import asyncio
import argparse
import csv
import json
import os
import sys
from dataclasses import asdict
from datetime import datetime

from .crawler import BrokenLinkFinder, BrokenLink
from .contacts import ContactFinder


def load_targets(filepath: str) -> list:
    targets = []
    with open(filepath, "r", encoding="utf-8") as f:
        reader = csv.DictReader(f)
        for row in reader:
            targets.append({
                "url": row["Target URL"],
                "label": row.get("University", row.get("Label", "")),
                "tier": row.get("Tier", ""),
                "category": row.get("Category", ""),
            })
    return targets


def load_processed(filepath: str) -> set:
    if not os.path.exists(filepath):
        return set()
    try:
        with open(filepath, "r") as f:
            data = json.load(f)
            return set(data.get("processed", []))
    except (json.JSONDecodeError, IOError):
        return set()


def save_processed(url: str, filepath: str):
    os.makedirs(os.path.dirname(filepath) or ".", exist_ok=True)
    if os.path.exists(filepath):
        try:
            with open(filepath, "r") as f:
                data = json.load(f)
        except (json.JSONDecodeError, IOError):
            data = {"processed": []}
    else:
        data = {"processed": []}

    if url not in data["processed"]:
        data["processed"].append(url)
    data["last_updated"] = datetime.now().isoformat()

    with open(filepath, "w") as f:
        json.dump(data, f, indent=2)


def save_results(broken_links: list, output_path: str):
    if not broken_links:
        print("No broken links found.")
        return

    os.makedirs(os.path.dirname(output_path) or ".", exist_ok=True)

    fieldnames = [
        "source_label", "source_url", "broken_url", "anchor_text",
        "surrounding_context", "status_code", "error_message",
        "found_at", "contact_emails",
    ]

    with open(output_path, "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=fieldnames)
        writer.writeheader()
        for link in broken_links:
            row = asdict(link)
            row["contact_emails"] = "; ".join(row["contact_emails"])
            writer.writerow(row)

    print(f"\nResults saved to: {output_path}")
    print(f"Total broken links found: {len(broken_links)}")


async def run(args):
    if not os.path.exists(args.input):
        print(f"Error: Input file not found: {args.input}")
        sys.exit(1)

    targets = load_targets(args.input)
    print(f"Loaded {len(targets)} target URLs")

    processed_file = os.path.join(os.path.dirname(args.output), "processed-urls.json")

    if not args.force:
        processed = load_processed(processed_file)
        original = len(targets)
        targets = [t for t in targets if t["url"] not in processed]
        skipped = original - len(targets)
        if skipped > 0:
            print(f"Skipping {skipped} already-processed URLs")

    if args.limit:
        targets = targets[: args.limit]

    if not targets:
        print("No new URLs to process!")
        return

    all_broken = []
    contact_finder = ContactFinder()

    async with BrokenLinkFinder(delay=args.delay) as finder:
        for target in targets:
            # Fetch page for both link checking and contact extraction
            html, status, error = await finder.fetch_page(target["url"])
            contacts = []
            if html:
                contacts = await contact_finder.find_emails(target["url"], page_html=html)
                if contacts:
                    print(f"  Contacts: {', '.join(contacts[:3])}")

            result = await finder.crawl_page(
                target["url"], label=target["label"], contact_emails=contacts
            )
            all_broken.extend(result.broken_links)
            save_processed(target["url"], processed_file)
            await asyncio.sleep(args.delay * 2)

    save_results(all_broken, args.output)

    print(f"\nSummary:")
    print(f"  Pages crawled: {len(targets)}")
    print(f"  Broken links found: {len(all_broken)}")


def main():
    parser = argparse.ArgumentParser(description="Find broken links on web pages")
    parser.add_argument("--input", "-i", default="broken-link-targets.csv")
    parser.add_argument("--output", "-o", default="output/broken-links-results.csv")
    parser.add_argument("--delay", "-d", type=float, default=1.0)
    parser.add_argument("--limit", "-l", type=int, default=None)
    parser.add_argument("--force", "-f", action="store_true")
    args = parser.parse_args()

    asyncio.run(run(args))


if __name__ == "__main__":
    main()
