from .constants import *

URL_BASE = "https://www.python.org/ftp/python/"

XYZ_VERSION = f"{VER_MAJOR}.{VER_MINOR}.{VER_MICRO}"
WIN32_VERSION = f"{VER_MAJOR}.{VER_MINOR}.{VER_MICRO}.{VER_FIELD4}"
FULL_VERSION = f"{VER_MAJOR}.{VER_MINOR}.{VER_MICRO}{VER_SUFFIX}"


def _not_empty(n, key=None):
    result = []
    for i in n:
        if key:
            i_l = i[key]
        else:
            i_l = i
        if not i_l:
            continue
        result.append(i)
    return result


def calculate_install_json(ns, *, for_embed=False, for_test=False):
    TARGET = "python.exe"
    TARGETW = "pythonw.exe"

    SYS_ARCH = {
        "win32": "32bit",
        "amd64": "64bit",
        "arm64": "64bit", # Unfortunate, but this is how it's spec'd
    }[ns.arch]
    TAG_ARCH = {
        "win32": "-32",
        "amd64": "-64",
        "arm64": "-arm64",
    }[ns.arch]

    COMPANY = "PythonCore"
    DISPLAY_NAME = "Python"
    TAG_SUFFIX = ""
    ALIAS_PREFIX = "python"
    ALIAS_WPREFIX = "pythonw"
    FILE_PREFIX = "python-"
    FILE_SUFFIX = f"-{ns.arch}"
    DISPLAY_TAGS = [{
        "win32": "32-bit",
        "amd64": "",
        "arm64": "ARM64",
    }[ns.arch]]

    if for_test:
        # Packages with the test suite come under a different Company
        COMPANY = "PythonTest"
        DISPLAY_TAGS.append("with tests")
        FILE_SUFFIX = f"-test-{ns.arch}"
    if for_embed:
        # Embeddable distro comes under a different Company
        COMPANY = "PythonEmbed"
        TARGETW = None
        ALIAS_PREFIX = None
        ALIAS_WPREFIX = None
        DISPLAY_TAGS.append("embeddable")
        # Deliberately name the file differently from the existing distro
        # so we can republish old versions without replacing files.
        FILE_SUFFIX = f"-embeddable-{ns.arch}"
    if ns.include_freethreaded:
        # Free-threaded distro comes with a tag suffix
        TAG_SUFFIX = "t"
        TARGET = f"python{VER_MAJOR}.{VER_MINOR}t.exe"
        TARGETW = f"pythonw{VER_MAJOR}.{VER_MINOR}t.exe"
        DISPLAY_TAGS.append("free-threaded")
        FILE_SUFFIX = f"t-{ns.arch}"

    FULL_TAG = f"{VER_MAJOR}.{VER_MINOR}.{VER_MICRO}{VER_SUFFIX}{TAG_SUFFIX}"
    FULL_ARCH_TAG = f"{FULL_TAG}{TAG_ARCH}"
    XY_TAG = f"{VER_MAJOR}.{VER_MINOR}{TAG_SUFFIX}"
    XY_ARCH_TAG = f"{XY_TAG}{TAG_ARCH}"
    X_TAG = f"{VER_MAJOR}{TAG_SUFFIX}"
    X_ARCH_TAG = f"{X_TAG}{TAG_ARCH}"

    # Tag used in runtime ID (for side-by-side install/updates)
    ID_TAG = XY_ARCH_TAG
    # Tag shown in 'py list' output
    DISPLAY_TAG = f"{XY_TAG}-dev{TAG_ARCH}" if VER_SUFFIX else XY_ARCH_TAG
    # Tag used for PEP 514 registration
    SYS_WINVER = XY_TAG + (TAG_ARCH if TAG_ARCH != '-64' else '')

    DISPLAY_SUFFIX = ", ".join(i for i in DISPLAY_TAGS if i)
    if DISPLAY_SUFFIX:
        DISPLAY_SUFFIX = f" ({DISPLAY_SUFFIX})"
    DISPLAY_VERSION = f"{XYZ_VERSION}{VER_SUFFIX}{DISPLAY_SUFFIX}"

    STD_RUN_FOR = []
    STD_ALIAS = []
    STD_PEP514 = []
    STD_START = []
    STD_UNINSTALL = []

    # The list of 'py install <TAG>' tags that will match this runtime.
    # Architecture should always be included here because PyManager will add it.
    INSTALL_TAGS = [
        FULL_ARCH_TAG,
        XY_ARCH_TAG,
        X_ARCH_TAG,
        # X_TAG and XY_TAG doesn't include VER_SUFFIX, so create -dev versions
        f"{XY_TAG}-dev{TAG_ARCH}" if XY_TAG and VER_SUFFIX else "",
        f"{X_TAG}-dev{TAG_ARCH}" if X_TAG and VER_SUFFIX else "",
    ]

    # Generate run-for entries for each target.
    # Again, include architecture because PyManager will add it.
    for base in [
        {"target": TARGET},
        {"target": TARGETW, "windowed": 1},
    ]:
        if not base["target"]:
            continue
        STD_RUN_FOR.append({**base, "tag": FULL_ARCH_TAG})
        if XY_TAG:
            STD_RUN_FOR.append({**base, "tag": XY_ARCH_TAG})
        if X_TAG:
            STD_RUN_FOR.append({**base, "tag": X_ARCH_TAG})
        if VER_SUFFIX:
            STD_RUN_FOR.extend([
                {**base, "tag": f"{XY_TAG}-dev{TAG_ARCH}" if XY_TAG else ""},
                {**base, "tag": f"{X_TAG}-dev{TAG_ARCH}" if X_TAG else ""},
            ])

    # Generate alias entries for each target. We need both arch and non-arch
    # versions as well as windowed/non-windowed versions to make sure that all
    # necessary aliases are created.
    for prefix, base in (
        (ALIAS_PREFIX, {"target": TARGET}),
        (ALIAS_WPREFIX, {"target": TARGETW, "windowed": 1}),
    ):
        if not prefix:
            continue
        if not base["target"]:
            continue
        if XY_TAG:
            STD_ALIAS.extend([
                {**base, "name": f"{prefix}{XY_TAG}.exe"},
                {**base, "name": f"{prefix}{XY_ARCH_TAG}.exe"},
            ])
        if X_TAG:
            STD_ALIAS.extend([
                {**base, "name": f"{prefix}{X_TAG}.exe"},
                {**base, "name": f"{prefix}{X_ARCH_TAG}.exe"},
            ])

    if SYS_WINVER:
        STD_PEP514.append({
            "kind": "pep514",
            "Key": rf"{COMPANY}\{SYS_WINVER}",
            "DisplayName": f"{DISPLAY_NAME} {DISPLAY_VERSION}",
            "SupportUrl": "https://www.python.org/",
            "SysArchitecture": SYS_ARCH,
            "SysVersion": VER_DOT,
            "Version": FULL_VERSION,
            "InstallPath": {
                "_": "%PREFIX%",
                "ExecutablePath": f"%PREFIX%{TARGET}",
                # WindowedExecutablePath is added below
            },
            "Help": {
                "Online Python Documentation": {
                    "_": f"https://docs.python.org/{VER_DOT}/"
                },
            },
        })

    STD_START.append({
        "kind": "start",
        "Name": f"{DISPLAY_NAME} {VER_DOT}{DISPLAY_SUFFIX}",
        "Items": [
            {
                "Name": f"{DISPLAY_NAME} {VER_DOT}{DISPLAY_SUFFIX}",
                "Target": f"%PREFIX%{TARGET}",
                "Icon": f"%PREFIX%{TARGET}",
            },
            {
                "Name": f"{DISPLAY_NAME} {VER_DOT} Online Documentation",
                "Icon": r"%SystemRoot%\System32\SHELL32.dll",
                "IconIndex": 13,
                "Target": f"https://docs.python.org/{VER_DOT}/",
            },
            # IDLE and local documentation items are added below
        ],
    })

    if TARGETW and STD_PEP514:
        STD_PEP514[0]["InstallPath"]["WindowedExecutablePath"] = f"%PREFIX%{TARGETW}"

    if ns.include_idle:
        STD_START[0]["Items"].append({
            "Name": f"IDLE (Python {VER_DOT}{DISPLAY_SUFFIX})",
            "Target": f"%PREFIX%{TARGETW or TARGET}",
            "Arguments": r'"%PREFIX%Lib\idlelib\idle.pyw"',
            "Icon": r"%PREFIX%Lib\idlelib\Icons\idle.ico",
            "IconIndex": 0,
        })
        STD_START[0]["Items"].append({
            "Name": f"PyDoc (Python {VER_DOT}{DISPLAY_SUFFIX})",
            "Target": f"%PREFIX%{TARGET}",
            "Arguments": "-m pydoc -b",
            "Icon": r"%PREFIX%Lib\idlelib\Icons\idle.ico",
            "IconIndex": 0,
        })
        if STD_PEP514:
            STD_PEP514[0]["InstallPath"]["IdlePath"] = f"%PREFIX%Lib\\idlelib\\idle.pyw"

    if ns.include_html_doc:
        STD_PEP514[0]["Help"]["Main Python Documentation"] = {
            "_": rf"%PREFIX%Doc\html\index.html",
        }
        STD_START[0]["Items"].append({
            "Name": f"{DISPLAY_NAME} {VER_DOT} Manuals{DISPLAY_SUFFIX}",
            "Target": r"%PREFIX%Doc\html\index.html",
        })
    elif ns.include_chm:
        STD_PEP514[0]["Help"]["Main Python Documentation"] = {
            "_": rf"%PREFIX%Doc\{PYTHON_CHM_NAME}",
        }
        STD_START[0]["Items"].append({
            "Name": f"{DISPLAY_NAME} {VER_DOT} Manuals{DISPLAY_SUFFIX}",
            "Target": "%WINDIR%hhc.exe",
            "Arguments": rf"%PREFIX%Doc\{PYTHON_CHM_NAME}",
        })

    STD_UNINSTALL.append({
        "kind": "uninstall",
        # Other settings will pick up sensible defaults
        "Publisher": "Python Software Foundation",
        "HelpLink": f"https://docs.python.org/{VER_DOT}/",
    })

    data = {
        "schema": 1,
        "id": f"{COMPANY.lower()}-{ID_TAG}",
        "sort-version": FULL_VERSION,
        "company": COMPANY,
        "tag": DISPLAY_TAG,
        "install-for": _not_empty(INSTALL_TAGS),
        "run-for": _not_empty(STD_RUN_FOR, "tag"),
        "alias": _not_empty(STD_ALIAS, "name"),
        "shortcuts": [
            *STD_PEP514,
            *STD_START,
            *STD_UNINSTALL,
        ],
        "display-name": f"{DISPLAY_NAME} {DISPLAY_VERSION}",
        "executable": rf".\{TARGET}",
        "url": f"{URL_BASE}{XYZ_VERSION}/{FILE_PREFIX}{FULL_VERSION}{FILE_SUFFIX}.zip"
    }

    return data
