#!/usr/bin/python3
# SPDX-License-Identifier: AGPL-3.0-only
# SPDX-FileCopyrightText: 2025 Univention GmbH

# Note:
# When changing this script please also consider changing (via gitlab):
# https://github.com/univention/container-udm-rest/blob/main/docker/ldap-update-univention-object-identifier/ldap-update-univention-object-identifier.py

import argparse
import logging
from pprint import pformat
from sys import exit, stderr

import univention.uldap
from univention.config_registry import ucr


logger = logging.getLogger(__name__)


def setup_logging(args: argparse.Namespace):
    log_format = "%(asctime)s %(levelname)-5s %(message)s" if not args.dry_run else '[dry-run] %(message)s'
    logging.basicConfig(format=log_format, level=args.log_level)


def update_univention_object_identifier(args: argparse.Namespace, lo: univention.uldap.access):
    result = lo.search(
        filter="(&(objectClass=univentionObject)(!(objectClass=univentionLicense))(!(univentionObjectIdentifier=*)))",
        attr=["univentionObjectIdentifier", "entryUUID"],
    )

    updated_count = 0
    failed_count = 0
    for dn, attr in result:
        logger.debug("Processing %s", dn)
        logger.debug("Values:\n%s", pformat(attr, indent=4))

        if attr.get("univentionObjectIdentifier") or not attr.get("entryUUID"):
            logger.warning(
                "Wrong ldap search condition! univentionObjectIdentifier: %s entryUUID: %s",
                attr.get("univentionObjectIdentifier"),
                attr.get("entryUUID"),
            )
            continue

        if not args.dry_run:
            logger.info('Update %r | %r', dn, attr['entryUUID'][0].decode('ASCII'))
            try:
                lo.modify(dn, [("univentionObjectIdentifier", None, attr["entryUUID"])])
            except Exception as exc:
                logger.error('Error: %s', exc)
                failed_count += 1
                continue
        else:
            logger.info('Would update %r | %r', dn, attr['entryUUID'][0].decode('ASCII'))

        updated_count += 1

    logger.info("Updated %s records.", updated_count)
    if failed_count:
        logger.warning("Failed to update %s records.", failed_count)

    if args.dry_run and updated_count:
        return 2

    return 1 if failed_count else 0


def main() -> int:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("-d", "--dry-run", action="store_true", help="perform dry run without changes")
    parser.add_argument("--log-level", default='INFO')
    args = parser.parse_args()
    setup_logging(args)

    if ucr.get("server/role") != "domaincontroller_master":
        logger.info("Script can only be run on a Primary Directory Node")
        return 0

    # ldap connection
    try:
        lo = univention.uldap.getRootDnConnection()
    except Exception as ex:
        print("failed to get ldap connection: %s" % (ex,), file=stderr)
        return 1

    logger.info("Updating univentionObjectIdentifier with entryUUID values.")

    return update_univention_object_identifier(args, lo)


if __name__ == "__main__":
    exit(main())
