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

from labels.artifact.relationship import (
    Relationship,
    RelationshipType,
)
from labels.file.dependency_type import (
    DependencyType,
)
from labels.file.location_read_closer import (
    LocationReadCloser,
)
from labels.file.resolver import (
    Resolver,
)
from labels.internal.collection.types import (
    IndexedDict,
    IndexedList,
    ParsedValue,
)
from labels.internal.collection.yaml import (
    parse_yaml_with_tree_sitter,
)
from labels.model.core import (
    Package,
)
from labels.pkg.cataloger.generic.parser import (
    Environment,
)
from labels.pkg.cataloger.swift.package import (
    new_cocoa_pods_package,
)

LOGGER = logging.getLogger(__name__)


def parse_podfile_lock(
    _: Resolver | None,
    __: Environment | None,
    reader: LocationReadCloser,
) -> tuple[list[Package], list[Relationship]]:
    try:
        podfile: IndexedDict[str, ParsedValue] = cast(
            IndexedDict[str, ParsedValue],
            parse_yaml_with_tree_sitter(reader.read_closer.read()),
        )
    except ValueError:
        return [], []

    if not podfile or "PODS" not in podfile:
        return [], []

    packages, dependencies_index = process_pods(podfile, reader)
    if not packages:
        return [], []

    relationships = generate_relations(dependencies_index, packages)

    return packages, relationships


def process_pods(
    podfile: IndexedDict[str, ParsedValue],
    reader: LocationReadCloser,
) -> tuple[list[Package], dict[str, list[str]]]:
    packages: list[Package] = []
    dependencies_index: dict[str, list[str]] = {}

    direct_dependencies = podfile["DEPENDENCIES"]
    pods = podfile["PODS"]
    if not isinstance(direct_dependencies, IndexedList) or not isinstance(pods, IndexedList):
        return [], {}

    for index, pod in enumerate(pods):
        pod_name, pod_version = extract_pod_info(pod)
        if not pod_name or not pod_version:
            return [], {}

        pod_root_package = pod_name.split("/")[0]
        checksums = podfile["SPEC CHECKSUMS"]
        if not isinstance(checksums, IndexedDict):
            return [], {}

        new_location = deepcopy(reader.location)
        if new_location.coordinates:
            new_location.dependency_type = (
                DependencyType.DIRECT
                if pod_name in direct_dependencies
                else DependencyType.TRANSITIVE
            )
            new_location.coordinates.line = pods.get_position(index).start.line

        if pkg := new_cocoa_pods_package(
            pod_name,
            pod_version,
            checksums[pod_root_package],
            new_location,
        ):
            packages.append(pkg)
            dependencies_index[pod_name] = dependencies_index.get(pod_name, [])

    return packages, dependencies_index


def extract_pod_info(pod: ParsedValue) -> tuple[str, str]:
    if isinstance(pod, str | IndexedDict):
        pod_blob = pod if isinstance(pod, str) else next(iter(pod))
        pod_name = pod_blob.split(" ")[0]
        pod_version = pod_blob.split(" ")[1].strip("()")
        return pod_name, pod_version
    return "", ""


def generate_relations(
    dependencies_index: dict[str, list[str]],
    packages: list[Package],
) -> list[Relationship]:
    relationships: list[Relationship] = []
    for package_name, dependencies in dependencies_index.items():
        package = next(x for x in packages if x.name == package_name)
        relationships.extend(
            Relationship(
                from_=package_dep,
                to_=package,
                type=RelationshipType.DEPENDENCY_OF_RELATIONSHIP,
            )
            for dependency in dependencies
            if (
                package_dep := next(
                    (x for x in packages if x.name == dependency.split(" ")[0]),
                    None,
                )
            )
        )

    return relationships
