import re
from reveallldb.supported_architecture import SupportedArchitecture
from reveallldb.supported_platform import SupportedPlatform
from reveallldb.supported_platform_variant import SupportedPlatformVariant
from typing import List, Match, Optional

class SupportedTarget:
    def __init__(self, architecture: SupportedArchitecture, platform: SupportedPlatform, variant: Optional[SupportedPlatformVariant]):
        self.architecture = architecture
        self.platform = platform
        self.variant = variant

    @classmethod
    def from_lldb_target_triple(cls, lldb_target_triple: str):
        # Extract the architecture, platform and target from the provided target's triple:
        matches: Optional[Match[str]] = re.search( r'([^-]+)-[^-]+-([a-z]+)([^-]+)?-?(.*)?', lldb_target_triple, re.M | re.I)

        if matches is None:
            return None

        extractedArchitecture = matches.group(1) # ie. x86_64, armv7, etc
        if extractedArchitecture:
            try:
                architecture = SupportedArchitecture(extractedArchitecture)
            except ValueError:
                return None
        else:
            return None

        if architecture not in SupportedArchitecture:
            return None
        elif architecture == SupportedArchitecture.x86_64h:
            # We don't actually ship an x86_64h slice, so redact the "h"
            architecture = SupportedArchitecture.x86_64
        elif architecture == SupportedArchitecture.arm64e:
            architecture = SupportedArchitecture.arm64

        extractedPlatform = matches.group(2) # ie. ios, tvos, etc
        if extractedPlatform:
            try:
                platform = SupportedPlatform(extractedPlatform)
            except ValueError:
                return None
        else:
            return None

        if platform not in SupportedPlatform:
            return None

        extractedVariant = matches.group(4) # ie. macabi, or nothing for all other targets
        if extractedVariant:
            try:
                variant = SupportedPlatformVariant(extractedVariant)
            except ValueError:
                variant = None
        else:
            variant = None

        if variant == SupportedPlatformVariant.macABI:
            # There is a mismatch between what LLDB refers to Mac Catalyst apps as, and how Xcode names XCFramework targets. Workaround this difference:
            variant = SupportedPlatformVariant.macCatalyst
        elif variant not in SupportedPlatformVariant and variant is not None:
            return None

        return SupportedTarget(architecture, platform, variant)

    def __repr__(self):
        return f"SupportedTarget({self.architecture}, {self.platform}, {self.variant})"

    def __eq__(self, other):
        if isinstance(other, SupportedTarget):
            return (self.architecture, self.platform, self.variant) == (other.architecture, other.platform, other.variant)
        else:
            return False

    def framework_slice(self, variants: List[str]) -> Optional[str]:
        regex = re.compile(r'([^-]+)-([^-]+)(-(.*))?', re.M | re.I)

        for framework_variant in variants:
            results = regex.search(framework_variant)

            if results:
                try:
                    platform: SupportedPlatform = SupportedPlatform(results.group(1)) # ie. ios, tvos, etc
                except ValueError:
                    continue

                if platform not in SupportedPlatform:
                    continue

                # The replacement command below makes a big assumption: that the array of architectures will only have two entries. We make this assumption because the delimiter that is used is an underscore (_), however the 64-bit x86 architecture *has an underscore in it's name* :facepalm:. We need a more reliable way of extracting recognizable architectures from the framework variant name.
                extractedArchitectures = results.group(2).replace("_", ",", 1).split(",")
                try:
                    architectures: List[SupportedArchitecture] = list(map(lambda name: SupportedArchitecture(name), extractedArchitectures)) # ie. armv7_arm64_arm64e, x86_64, etc
                except ValueError:
                    continue

                if not architectures:
                    continue

                extractedVariant = results.group(4) # ie. maccatalyst, simulator, or nothing for actual devices
                if extractedVariant:
                    try:
                        variant = SupportedPlatformVariant(extractedVariant)
                    except ValueError:
                        variant = None
                else:
                    variant = None

                if variant not in SupportedPlatformVariant and variant is not None:
                    continue

                if (self.platform == platform and
                    self.architecture in architectures and
                    self.variant == variant):
                    return framework_variant
                else:
                    continue

        return None
