import re
from copy import (
    deepcopy,
)
from typing import cast

from labels.artifact.relationship import (
    Relationship,
)
from labels.file.dependency_type import (
    DependencyType,
)
from labels.file.location import (
    Location,
)
from labels.file.location_read_closer import (
    LocationReadCloser,
)
from labels.file.resolver import (
    Resolver,
)
from labels.file.scope import (
    Scope,
)
from labels.model.core import (
    Language,
    Package,
    PackageType,
)
from labels.pkg.cataloger.generic.parser import (
    Environment,
)

from .package import (
    package_url,
)

MIX_DEP: re.Pattern[str] = re.compile(
    r"\{:(?P<dep>[\w]*),\s\"~>\s(?P<version>[\d.]+)\".+",
)


def _get_location(
    reader: LocationReadCloser,
    line_number: int,
    *,
    is_dev: bool,
) -> Location:
    location = deepcopy(reader.location)
    location.scope = Scope.DEV if is_dev else Scope.PROD
    if location.coordinates:
        location.coordinates.line = line_number
        location.dependency_type = DependencyType.DIRECT
    return location


def parse_mix_exs(
    _: Resolver | None,
    __: Environment | None,
    reader: LocationReadCloser,
) -> tuple[list[Package], list[Relationship]]:
    packages: list[Package] = []
    relationships: list[Relationship] = []
    is_line_deps = False

    for line_number, raw_line in enumerate(
        reader.read_closer.read().splitlines(),
        1,
    ):
        line = raw_line.strip()
        if line == "defp deps do":
            is_line_deps = True
        elif is_line_deps:
            if line == "end":
                break
            if matched := MIX_DEP.match(line):
                is_dev = ":dev" in line
                pkg_name = cast(str, matched.group("dep"))
                pkg_version = cast(str, matched.group("version"))
                location = _get_location(reader, line_number, is_dev=is_dev)

                packages.append(
                    Package(
                        name=pkg_name,
                        version=pkg_version,
                        type=PackageType.HexPkg,
                        locations=[location],
                        p_url=package_url(pkg_name, pkg_version),
                        metadata=None,
                        language=Language.ELIXIR,
                        licenses=[],
                        is_dev=is_dev,
                    ),
                )
    return packages, relationships
