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

from labels.artifact.relationship import (
    Relationship,
)
from labels.file.location_read_closer import (
    LocationReadCloser,
)
from labels.file.resolver import (
    Resolver,
)
from labels.internal.collection.json import (
    parse_json_with_tree_sitter,
)
from labels.internal.collection.types import (
    IndexedDict,
    IndexedList,
    ParsedValue,
)
from labels.model.core import (
    Package,
)
from labels.pkg.cataloger.generic.parser import (
    Environment,
)
from labels.pkg.cataloger.swift.package import (
    new_swift_package_manager_package,
)

LOGGER = logging.getLogger(__name__)
EMPTY_DICT: IndexedDict[str, ParsedValue] = IndexedDict()
EMPTY_LIST: IndexedList[ParsedValue] = IndexedList()


def _get_name_and_version(
    pin: ParsedValue,
) -> tuple[str, str, IndexedDict[str, ParsedValue]] | None:
    if not isinstance(pin, IndexedDict):
        return None
    state: ParsedValue = pin.get("state", EMPTY_DICT)
    name = pin.get("identity")
    if not isinstance(state, IndexedDict):
        return None
    version = state.get("version")

    if not name or not version or not isinstance(version, str) or not isinstance(name, str):
        return None

    return name, version, state


def parse_package_resolved(
    _: Resolver | None,
    __: Environment | None,
    reader: LocationReadCloser,
) -> tuple[list[Package], list[Relationship]]:
    package_resolved: IndexedDict[str, ParsedValue] = cast(
        IndexedDict[str, ParsedValue],
        parse_json_with_tree_sitter(reader.read_closer.read()),
    )

    packages: list[Package] = []
    relationships: list[Relationship] = []
    package_resolved_pins: ParsedValue = package_resolved.get("pins", EMPTY_LIST)

    if isinstance(package_resolved_pins, IndexedList):
        for pin in package_resolved_pins:
            if not isinstance(pin, IndexedDict):
                continue
            info = _get_name_and_version(pin)
            if not info:
                continue
            new_location = deepcopy(reader.location)
            if new_location.coordinates:
                new_location.coordinates.line = pin.position.start.line

            if pkg := new_swift_package_manager_package(
                name=info[0],
                version=info[1],
                source_url=pin.get("location"),
                revision=info[2].get("revision"),
                location=new_location,
            ):
                packages.append(pkg)

    return packages, relationships
