#!/usr/bin/python3
#
# Copyright (c) 2023--2025 SUSE LLC
#
# This software is licensed to you under the GNU General Public License,
# version 2 (GPLv2). There is NO WARRANTY for this software, express or
# implied, including the implied warranties of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
# along with this software; if not, see
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
#
#  pylint: disable=missing-module-docstring,invalid-name

import re
import sys
import os
import os.path
import uuid
import shutil
import subprocess
from spacewalk.common.rhnConfig import cfg_component
from spacewalk.server import rhnSQL


def run_uyuni_configfiles_sync():
    if not os.path.isfile("/usr/bin/uyuni-configfiles-sync"):
        return 0

    exitCode = 0
    result = subprocess.run(
        ["/usr/bin/uyuni-configfiles-sync", "sync"],
        stdout=subprocess.PIPE,
        stderr=subprocess.STDOUT,
        encoding="utf-8",
        check=False,
    )

    if result.stdout:
        sys.stdout.write(f"{result.stdout}\n")
        sys.stdout.flush()
    if result.returncode:
        sys.stdout.write(
            "Failed to synchronize files to persistent volumes. Aborting!\n"
        )
        sys.stdout.flush()
        exitCode = 1
    return exitCode


def move_config_to_db():
    """
    Move specific configuration values from /etc/rhn/rhn.conf into rhnConfigration table
    """
    rhnSQL.initDB()

    # pylint: disable-next=invalid-name
    with cfg_component("server") as CFG:
        if CFG.has_key("server.max_passwd_len"):
            move_configuration(
                "PSW_CHECK_LENGTH_MAX",
                CFG.max_passwd_len,
                oldkey="server.max_passwd_len",
            )
        elif CFG.has_key("max_passwd_len"):
            move_configuration(
                "PSW_CHECK_LENGTH_MAX", CFG.max_passwd_len, oldkey="max_passwd_len"
            )

        if CFG.has_key("server.min_passwd_len"):
            move_configuration(
                "PSW_CHECK_LENGTH_MIN",
                CFG.max_passwd_len,
                oldkey="server.min_passwd_len",
            )
        elif CFG.has_key("min_passwd_len"):
            move_configuration(
                "PSW_CHECK_LENGTH_MIN", CFG.min_passwd_len, oldkey="min_passwd_len"
            )


def move_configuration(key, value, oldkey=None):
    h = rhnSQL.prepare(
        """
            UPDATE rhnConfiguration SET value = :val WHERE key = :key
            """
    )
    rowcount = h.execute(val=value, key=key)
    if rowcount != 1:
        # update failed
        sys.stdout.write(f"Failed to move {key} into DB\n")
        sys.stdout.flush()
        return
    with open("/etc/rhn/rhn.conf", "r+", encoding="utf8") as f:
        new_f = f.readlines()
        f.seek(0)
        for line in new_f:
            if oldkey:
                if not line.strip().startswith(oldkey):
                    f.write(line)
            elif not line.strip().startswith(key):
                f.write(line)
        f.truncate()


def init_scc_login():
    # pylint: disable-next=invalid-name
    with cfg_component("server.susemanager") as CFG:
        try:
            if CFG.scc_backup_srv_usr:
                # nothing to do
                return
        except AttributeError:
            # key does not exist, we need to create it
            pass

    scc_cred_file = "/etc/zypp/credentials.d/SCCcredentials"

    uuid_num = None
    if os.path.exists(scc_cred_file):
        with open(scc_cred_file, "r", encoding="utf8") as f:
            for line in f:
                if line.startswith("username"):
                    _, v = line.split("=", 2)
                    uuid_num = v.strip()
                    break
    if not uuid_num:
        # scc expects either a SCC machine login (must exists in SCC)
        # or a UUID4 following rfc4122 to identify a anonyme proxy
        uuid_num = str(uuid.uuid4())
    with open("/etc/rhn/rhn.conf", "a", encoding="utf8") as r:
        r.write("\n")
        r.write(f"server.susemanager.scc_backup_srv_usr = {uuid_num}\n")


def import_suma_gpg_keyring():

    result = subprocess.run(
        ["/usr/sbin/import-suma-build-keys"],
        stdout=subprocess.PIPE,
        stderr=subprocess.STDOUT,
        encoding="utf-8",
        check=False,
    )

    if result.returncode:
        sys.stdout.write("Failed to import SUSE Manager Build Keys\n")
    if result.stdout:
        sys.stdout.write(f"{result.stdout}\n")
    sys.stdout.flush()


def copy_ca():
    result = subprocess.run(
        [
            "cp",
            "/etc/pki/trust/anchors/LOCAL-RHN-ORG-TRUSTED-SSL-CERT",
            "/usr/share/susemanager/salt/certs/RHN-ORG-TRUSTED-SSL-CERT",
        ],
        stdout=subprocess.PIPE,
        stderr=subprocess.STDOUT,
        encoding="utf-8",
        check=False,
    )

    if result.returncode:
        sys.stdout.write("Failed to copy the CA certificate to the Salt Filesystem\n")
    if result.stdout:
        sys.stdout.write(f"{result.stdout}\n")
    sys.stdout.flush()


def change_billing_data_service():
    sysconf = "/etc/sysconfig/billing-data-service"
    content = []
    changed = False
    if os.path.exists(sysconf):
        with open(sysconf, "r", encoding="utf8") as f:
            for line in f:
                line = line.strip()
                if line == 'LISTEN="127.0.0.1"':
                    line = 'LISTEN="0.0.0.0"'
                    changed = True
                content.append(line)

        if not changed:
            sys.stdout.write("billing-data-service sysconfig file unchanged\n")
            return
        with open(sysconf, "w", encoding="utf8") as r:
            for line in content:
                r.write(f"{line}\n")
        sys.stdout.write("billing-data-service sysconfig: changed LISTEN address\n")


def init_dirs_and_perms():
    mount_point = "/var/spacewalk"
    with cfg_component("server") as CFG:
        mount_point = CFG.MOUNT_POINT
    if not mount_point:
        sys.stdout.write("Invalid mount point. Aborting!\n")
        sys.stdout.flush()
        sys.exit(1)

    # mount_point/systems dir with 775 wwwrun www
    system_dir = os.path.join(mount_point, "systems")
    if not os.path.exists(system_dir):
        try:
            os.makedirs(system_dir)
        except OSError as e:
            sys.stdout.write(f"Failed to create directory {system_dir}: {e}")
            sys.exit(1)

    shutil.chown(system_dir, "wwwrun", "www")
    os.chmod(system_dir, int("0775", 8))


def remove_product_name_overwrite():
    pattern = re.compile(r"^product_name\s*=.*$")
    with open("/etc/rhn/rhn.conf", "r+", encoding="utf8") as f:
        new_f = f.readlines()
        f.seek(0)
        for line in new_f:
            if not pattern.match(line.strip()):
                f.write(line)
        f.truncate()


def change_hostname():
    result = subprocess.run(
        ["/usr/bin/spacewalk-hostname-rename"],
        stdout=subprocess.PIPE,
        stderr=subprocess.STDOUT,
        encoding="utf-8",
        check=False,
    )

    if result.returncode:
        sys.stdout.write("Failed to rename the server\n")
    if result.stdout:
        sys.stdout.write(f"{result.stdout}\n")
    sys.stdout.flush()
    return result.returncode


def main():
    init_dirs_and_perms()
    exitCode = run_uyuni_configfiles_sync()
    init_scc_login()
    import_suma_gpg_keyring()
    copy_ca()
    move_config_to_db()
    change_billing_data_service()
    remove_product_name_overwrite()

    exitCode = max(change_hostname(), exitCode)
    return exitCode

if __name__ == "__main__":
    sys.exit(abs(main() or 0))
