from pathlib import Path
from typing import Optional
from typing import Tuple
from typing import Union
import requests


def check_link(link: str, path: Path) -> Optional[Tuple[Path, str, str]]:
    """Checks if the link/ref is valid. For HTTP response status codes
    handling, we flag all 4xx (client errors) for broken links.

    Args:
        link (str): An external link or a reference to another document that is
            found in the currently parsed file.
        path (Path): Path to the .md/.rst file containing that being parsed.

    Returns:
        (Optional[Tuple[Path, str, str]]): None when `link` is valid. A tuple
        containing (path of file being parsed, link/ref, root directory/error
        code) when the link/ref is faulty.
    """
    rel_path = path.relative_to(Path.cwd())

    def faulty_link_info(root_or_error: Union[int, str, Path]) -> Tuple[Path, str, str]:
        return rel_path, link, str(root_or_error)

    if link.startswith("http"):
        try:
            response = requests.get(link, timeout=10)
            if 400 <= response.status_code < 500:
                return faulty_link_info(response.status_code)
        except requests.exceptions.Timeout:
            return faulty_link_info("timed out")
        except requests.RequestException:
            pass
    else:
        if not (path.parent / link).exists():
            condition = ["/peekingduck", "pipeline", "nodes"]
            if link.split(".")[:3] != condition:
                rel_path = path.relative_to(Path.cwd())
                return faulty_link_info(rel_path.parent)
    return None