#     Copyright 2026, Kay Hayen, mailto:kay.hayen@gmail.com find license text at end of file


"""For macOS DMG file creation"""

import os
import shutil

from nuitka.freezer.IncludedDataFiles import getIncludedDataFiles
from nuitka.freezer.MacOSApp import getMacOSIconPaths
from nuitka.OutputDirectories import (
    getResultBasePath,
    getStandaloneDirectoryPath,
)
from nuitka.plugins.Hooks import onInstallerOutput
from nuitka.Tracing import installer_logger
from nuitka.utils.Execution import (
    executeToolChecked,
    filterOutputByLine,
    getExecutablePath,
)
from nuitka.utils.FileOperations import (
    changeFilenameExtension,
    copyFile,
    deleteFile,
    makePath,
    removeDirectory,
)
from nuitka.utils.Signing import addMacOSCodeSignature


def _filterCreateDmgOutput(stderr):
    def isNonErrorExit(line):
        if b".DS_STORE to be created" in line:
            return True
        if b"Searching for mounted" in line:
            return True

        return False

    return filterOutputByLine(stderr, isNonErrorExit)


def getCreateDmgPath():
    create_dmg_path = getExecutablePath("create-dmg")

    if create_dmg_path is not None:
        return create_dmg_path

    for create_dmg_path in (
        "/opt/homebrew/bin/create-dmg",
        "/usr/local/bin/create-dmg",
    ):
        if os.path.exists(create_dmg_path):
            return create_dmg_path

    return None


def createMacOSDmg():
    """Create a DMG file for the application bundle.

    Returns:
        Filename of the created DMG artifact, or None if none was created.
    """
    create_dmg_path = getCreateDmgPath()

    app_bundle_path = getStandaloneDirectoryPath(bundle=False, real=True)

    external_files = [
        included_datafile
        for included_datafile in getIncludedDataFiles()
        if included_datafile.isExternal()
    ]

    if external_files:
        staging_dir = app_bundle_path + ".dmg-stage"
        makePath(staging_dir)

        # spell-checker: ignore copytree
        shutil.copytree(
            app_bundle_path,
            os.path.join(staging_dir, os.path.basename(app_bundle_path)),
        )

        for included_datafile in external_files:
            dest_path = os.path.join(
                staging_dir, os.path.basename(included_datafile.dest_path)
            )
            copyFile(included_datafile.dest_path, dest_path)

        source_dir = staging_dir
    else:
        source_dir = app_bundle_path

    icon_paths = getMacOSIconPaths()

    dmg_path = changeFilenameExtension(app_bundle_path, ".dmg")
    deleteFile(dmg_path, must_exist=False)

    # spell-checker: ignore volname,volicon
    command = [
        create_dmg_path,
        "--volname",
        os.path.basename(getResultBasePath()),
        "--window-pos",
        "200",
        "120",
        "--window-size",
        "800",
        "400",
        "--icon-size",
        "100",
        "--icon",
        os.path.basename(app_bundle_path),
        "200",
        "190",
        "--hide-extension",
        os.path.basename(app_bundle_path),
        "--app-drop-link",
        "600",
        "185",
        dmg_path,
        source_dir,
    ]

    if icon_paths:
        command.extend(["--volicon", icon_paths[0]])

    installer_logger.info("Creating DMG file '%s'..." % dmg_path)

    executeToolChecked(
        logger=installer_logger,
        command=command,
        absence_message="Cannot find 'create-dmg' tool necessary to create DMG.",
        stderr_filter=_filterCreateDmgOutput,
    )

    addMacOSCodeSignature(filenames=[dmg_path], entitlements_filename=None)

    if external_files:
        removeDirectory(
            path=staging_dir,
            logger=installer_logger,
            ignore_errors=True,
            extra_recommendation=None,
        )

    onInstallerOutput(filename=dmg_path)

    installer_logger.info(
        "Created DMG file with the application bundle in it: '%s'." % dmg_path
    )

    return dmg_path


#     Part of "Nuitka", an optimizing Python compiler that is compatible and
#     integrates with CPython, but also works on its own.
#
#     Licensed under the GNU Affero General Public License, Version 3 (the "License");
#     you may not use this file except in compliance with the License.
#     You may obtain a copy of the License at
#
#        https://www.gnu.org/licenses/agpl-3.0.txt
#
#     See also: "Nuitka Runtime Library Exception, Version 1.0" in file
#     "LICENSE-RUNTIME.txt" for additional permissions granted under Section 7.
#
#     Unless required by applicable law or agreed to in writing, software
#     distributed under the License is distributed on an "AS IS" BASIS,
#     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#     See the License for the specific language governing permissions and
#     limitations under the License.
