from __future__ import annotations

from collections import deque
from urllib.parse import urljoin, urlparse

import requests
from bs4 import BeautifulSoup

from Mama.ingestion import ingest_documents
from Mama.models import ExecutionContext
from Mama.ports import RuntimePorts

try:
    from langchain_community.document_loaders import AsyncChromiumLoader  # type: ignore
    from langchain_community.document_transformers import BeautifulSoupTransformer  # type: ignore
except Exception:  # pragma: no cover
    from langchain.document_loaders import AsyncChromiumLoader  # type: ignore
    from langchain.document_transformers import BeautifulSoupTransformer  # type: ignore

try:
    from langchain_text_splitters import RecursiveCharacterTextSplitter  # type: ignore
except Exception:  # pragma: no cover
    from langchain.text_splitter import RecursiveCharacterTextSplitter  # type: ignore


def crawl_links(root_url: str, max_depth: int = 1) -> list[str]:
    if max_depth < 1:
        return []

    root = urlparse(root_url)
    domain = root.netloc
    visited: set[str] = set()
    collected: set[str] = set()
    queue = deque([(root_url, 0)])

    while queue:
        url, depth = queue.popleft()
        if url in visited or depth > max_depth:
            continue
        visited.add(url)

        try:
            response = requests.get(url, timeout=15)
            response.raise_for_status()
        except Exception:
            continue

        soup = BeautifulSoup(response.content, "html.parser")
        for anchor in soup.find_all("a", href=True):
            nxt = urljoin(url, str(anchor["href"]).split("#", 1)[0])
            parsed = urlparse(nxt)
            if parsed.netloc != domain:
                continue
            if nxt in collected:
                continue
            collected.add(nxt)
            if depth + 1 <= max_depth:
                queue.append((nxt, depth + 1))

    return sorted(collected)


def load_url_documents(urls: list[str], chunk_size: int = 500, chunk_overlap: int = 0):
    if not urls:
        return []

    html = AsyncChromiumLoader(urls).load()
    transformed = BeautifulSoupTransformer().transform_documents(html)
    splitter = RecursiveCharacterTextSplitter(chunk_size=chunk_size, chunk_overlap=chunk_overlap)
    return splitter.split_documents(transformed)


def ingest_urls(ctx: ExecutionContext, urls: list[str], runtime: RuntimePorts):
    documents = load_url_documents(urls)
    return ingest_documents(ctx, documents, runtime)
