#!/usr/bin/python3 -OO
# -*- coding: utf-8 -*-
#
# Univention UCS@school
#
# SPDX-FileCopyrightText: 2007-2026 Univention GmbH
# SPDX-License-Identifier: AGPL-3.0-only

from __future__ import print_function

import argparse
import csv
import sys
import traceback
from ipaddress import AddressValueError, IPv4Interface, NetmaskValueError  # noqa: F401

import univention.debug as ud
from ucsschool.importer.exceptions import ComputerImportError
from ucsschool.importer.utils.computer_import import (
    call_hook,
    get_ip_iface,
    mac_address_is_used,
)
from ucsschool.importer.utils.constants import get_sep_char
from ucsschool.importer.utils.utils import verify_school_ou
from ucsschool.lib.models.attributes import ValidationError
from ucsschool.lib.models.computer import (
    IPComputer,
    LinuxComputer,
    MacComputer,
    UbuntuComputer,
    WindowsComputer,
)
from ucsschool.lib.models.utils import stopped_notifier
from univention.admin.uexceptions import authFail, insufficientInformation
from univention.admin.uldap import access as LoType, getAdminConnection  # noqa: F401

ud.init("/var/log/univention/ucs-school-import.log", ud.FLUSH, ud.NO_FUNCTION)
ud.set_level(ud.MAIN, ud.ALL)


def import_computers(input_file):  # type: (str) -> None
    try:
        lo, _ = getAdminConnection()
    except authFail as exc:
        ud.debug(ud.MAIN, ud.WARN, "authentication error: %s" % (exc,))
        print("ERROR: authentication error: %s" % (exc,))
        sys.exit(13)
    print("input file is  : {}".format(input_file))
    line_number = 0
    computer_to_class_mapping = {
        "windows": WindowsComputer,
        "macos": MacComputer,
        "ipmanagedclient": IPComputer,
        "ubuntu": UbuntuComputer,
        "linux": LinuxComputer,
    }
    sep_char = get_sep_char()
    with open(input_file) as csv_file, stopped_notifier():
        reader = csv.reader(csv_file, delimiter=sep_char)
        for row in reader:
            line_number += 1
            if not row:
                continue
            computer_type = row[0]
            computer_name = row[1].lower()
            mac_address = row[2].replace("-", ":").replace(".", ":").lower()
            school_id = row[3]
            ip_address = row[4]
            inventory_numbers = None
            if len(row) > 5:
                inventory_numbers = row[5].strip().split(",")
            print("Processing line %d: %s\n" % (line_number, sep_char.join(row)), end=" ")

            if computer_type in computer_to_class_mapping:
                verify_school_ou(school_id, lo)
                _cls = computer_to_class_mapping[computer_type]
                computer = _cls(school=school_id, name=computer_name)
                if computer.exists(lo):
                    print("WARNING: computer %s already exists (school %s)" % (computer_name, school_id))
                    continue
                elif mac_address_is_used(mac_address, lo):
                    print(
                        "WARNING: mac_address %s for computer %s already used (school %s)"
                        % (
                            mac_address,
                            computer_name,
                            school_id,
                        )
                    )
                    continue
                # one mac address per computer
                computer.mac_address = [mac_address] if mac_address else []
                if inventory_numbers:
                    computer.inventory_number = inventory_numbers
                try:
                    ip_iface = get_ip_iface(ip_address)
                except ComputerImportError as exc:
                    print(sep_char.join(row))
                    raise exc

                computer.ip_address = [str(ip_iface.ip)]
                computer.subnet_mask = ip_iface.netmask
                if ip_iface.ip != ip_iface.network.network_address:
                    print("set ip to %s is not net %s" % (ip_iface.ip, ip_iface.network.network_address))
                call_hook(lo=lo, meth_name="pre_create", obj=computer, line=row)
                try:
                    computer.create(lo)
                except ValidationError:
                    print(
                        "WARNING: Error creating computer %s\n %s"
                        % (computer.dn, traceback.format_exc(100))
                    )
                except insufficientInformation:
                    # if ip | mac address is missing
                    print(
                        "WARNING: Error creating computer %s\n %s"
                        % (computer.dn, traceback.format_exc(100))
                    )
                call_hook(lo=lo, meth_name="post_create", obj=computer, line=row)
                print("Processing of line %d completed" % line_number)
            else:
                print(
                    "Importing computer {} with type {} is not supported".format(
                        computer_name, computer_type
                    )
                )
                print("Ignoring of line %d" % line_number)


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="UCS@school import computer tool",
    )
    parser.add_argument("inputfile", help="computer import file")
    options = parser.parse_args()
    import_computers(options.inputfile)
