from curses.ascii import isdigit
import enum


class os_data(enum.IntEnum):
    # OS Versions, Based off Major Kernel Version
    cheetah =       4 # Actually 1.3.1
    puma =          5
    jaguar =        6
    panther =       7
    tiger =         8
    leopard =       9
    snow_leopard =  10
    lion =          11
    mountain_lion = 12
    mavericks =     13
    yosemite =      14
    el_capitan =    15
    sierra =        16
    high_sierra =   17
    mojave =        18
    catalina =      19
    big_sur =       20
    monterey =      21
    ventura =       22
    max_os =        99


class os_conversion:

    def os_to_kernel(os):
        # Convert OS version to major XNU version
        if os.startswith("10."):
            return (int(os.split(".")[1]) + 4)
        else:
            return (int(os.split(".")[0]) + 9)

    def kernel_to_os(kernel):
        # Convert major XNU version to OS version
        if kernel >= os_data.big_sur:
            return str((kernel - 9))
        else:
            return str((f"10.{kernel - 4}"))

    def is_os_newer(source_major, source_minor, target_major, target_minor):
        # Check if OS version 1 is newer than OS version 2
        if source_major < target_major:
            return True
        elif source_major == target_major:
            if source_minor < target_minor:
                return True
            else:
                return False

    def convert_kernel_to_marketing_name(kernel):
        # Convert major XNU version to Marketing Name
        try:
            # Find os_data enum name
            os_name = os_data(kernel).name

            # Remove "_" from the string
            os_name = os_name.replace("_", " ")

            # Upper case the first letter of each word
            os_name = os_name.title()
        except ValueError:
            # Handle cases where no enum value exists
            # Pass kernel_to_os() as a substitute for a proper OS name
            os_name = os_conversion.kernel_to_os(kernel)

        return os_name

    def convert_marketing_name_to_kernel(marketing_name):
        # Convert Marketing Name to major XNU version
        try:
            # Find os_data enum value
            os_kernel = os_data[marketing_name.lower().replace(" ", "_")]
        except KeyError:
            os_kernel = 0

        return int(os_kernel)


    def find_largest_build(build_array):
        # Find the newest version within an array of versions
        # These builds will have both numbers and letters in the version
        # ex:
        # [
        #    "22A5295i",
        #    "22A5266r",
        #    "22A5286j",
        #    "22A5295h",
        # ]

        max_length =        0  # Length of the longest build
        build_array_split = [] # 'build_array', converted into individual array of elements
        final_build =       "" # Largest determined build


        # Convert strings to arrays
        for build in build_array:
            list_build = list(build)
            if len(list_build) > max_length:
                max_length = len(list_build)
            build_array_split.append(list_build)

        # Pad out each array to same length
        for build in build_array_split:
            while len(build) < max_length:
                build.append("0")

        # Convert all letters to int using ord()
        for build in build_array_split:
            for entry in build:
                if not entry.isdigit():
                    build[build.index(entry)] = ord(entry)

        for build_outer_loop in build_array_split:
            for build_inner_loop in list(build_array_split):
                for i in range(len(build_outer_loop)):
                    # remove any builds that are not the largest
                    if int(build_outer_loop[i]) > int(build_inner_loop[i]):
                        build_array_split.remove(build_inner_loop)
                        break
                    if int(build_outer_loop[i]) < int(build_inner_loop[i]):
                        break

        # Convert array back to string
        for entry in build_array_split[0]:
            # Since we split per character, we know that anything above 9 is a letter
            if int(entry) > 9:
                # revert back to letter
                final_build += chr(entry)
            else:
                final_build += str(entry)

        # Since we pad with 0s, we need to next determine how many 0s to remove
        for build in build_array:
            if final_build.startswith(build):
                # Handle cases where Apple added a letter to the build
                # ex. "22A5295" vs "22A5295"
                remaining_strings = final_build.split(build)[1]
                # If all remaining strings are 0s, then we can remove the 0s
                if all(char == "0" for char in remaining_strings):
                    final_build = build

        return final_build