# SPDX-License-Identifier: GPL-2.0-or-later
# SPDX-FileCopyrightText: 2011-2024 Blender Authors
# <pep8 compliant>

import json
import os

import worker.blender.pack
import worker.blender.sign
import worker.blender.version
import worker.blender.msix_package

import worker.deploy
import worker.utils


def _package_architecture(
    builder: worker.deploy.CodeStoreBuilder, architecture: str, dry_run: bool
) -> None:
    version_info = worker.blender.version.VersionInfo(builder)

    # Revision with MS Store must be set to 0
    revision_id = 0

    branches_config = builder.get_branches_config()
    is_lts = builder.track_id in branches_config.windows_store_lts_tracks
    base_build_number = 0

    build_number = version_info.patch + base_build_number
    worker.utils.info(f"Builder number {build_number}")

    store_version_id = f"{version_info.short_version}.{build_number}.{revision_id}"
    worker.utils.info(f"Store version ID {store_version_id}")

    worker.utils.info(f"Cleaning path [{builder.store_windows_dir}]")
    worker.utils.remove_dir(builder.store_windows_dir)
    os.makedirs(builder.store_windows_dir, exist_ok=True)

    os.chdir(builder.store_windows_dir)

    # Find input zip package.
    package_manifest = builder.package_dir / "manifest.json"
    builds = json.loads(package_manifest.read_text())
    input_file_path = None

    for build in builds:
        if (
            build["platform"] == "windows"
            and build["file_extension"] == "zip"
            and build["architecture"] == architecture
        ):
            input_file_path = builder.package_dir / build["file_name"]
            break
    if not input_file_path:
        raise Exception(
            f"Windows package not found in [{builder.package_dir}] manifest"
        )

    # Copy all required files into working folder
    source_path = builder.code_path / "release" / "windows" / "msix"
    dest_path = builder.store_windows_dir
    worker.utils.info(
        f"Copying [{source_path}] -> [{dest_path}] for windows store packaging"
    )

    for source_file in source_path.iterdir():
        if source_file.name == "README.md":
            continue
        if source_file.is_dir():
            worker.utils.copy_dir(source_file, dest_path / source_file.name)
        else:
            worker.utils.copy_file(source_file, dest_path / source_file.name)

    worker_config = builder.get_worker_config()

    cert_subject = worker_config.windows_store_certificate(builder.service_env_id)
    certificate_id = f"CN={cert_subject}"

    msix_filepath = worker.blender.msix_package.pack(
        store_version_id, input_file_path, certificate_id, lts=is_lts, dry_run=dry_run
    )

    if worker_config.windows_store_self_sign:
        worker.blender.sign.sign_windows_files(
            builder.service_env_id, [msix_filepath], certificate_id=certificate_id
        )

    if dry_run:
        msix_filepath.write_text("Dry run dummy package file")

    # Clear out all msix files first
    for old_msix_filepath in builder.package_dir.glob("*.msix"):
        worker.utils.remove_file(old_msix_filepath)

    dest_path = builder.package_dir / msix_filepath.name
    worker.utils.info(f"Copying [{msix_filepath}] -> [{dest_path}] for distribution")
    worker.utils.copy_file(msix_filepath, dest_path)
    worker.blender.pack.generate_file_hash(dest_path)


def package(builder: worker.deploy.CodeStoreBuilder) -> None:
    dry_run = False
    if not builder.platform == "windows":
        if builder.service_env_id == "LOCAL":
            worker.utils.warning("Performing dry run on LOCAL service environment")
            dry_run = True
        else:
            raise Exception("Can only run this on Windows, aborting")

    branches_config = builder.get_branches_config()
    expected_platforms = branches_config.code_official_platform_architectures[
        builder.track_id
    ]

    for expected_platform in expected_platforms:
        if expected_platform.startswith("windows"):
            architecture = expected_platform.split("-")[1]
            _package_architecture(builder, architecture, dry_run)


def deliver(builder: worker.deploy.CodeStoreBuilder) -> None:
    worker.utils.info("Windows store delivery not implemented")