#!/usr/bin/env python3

#########################################################
# 
# by Netzint GmbH 2025
# Lukas Spitznagel (lukas.spitznagel@netzint.de)
# 
#########################################################

import argparse
import subprocess
import socket
import os.path
import os
import sys

from getpass import getpass
from subprocess import PIPE

def __execute(command) -> subprocess.CompletedProcess:
    """
    Execute a command and return a subprocess.CompletedProcess object

    Args:
        command (list): List of strings representing the command to execute

    Returns:
        subprocess.CompletedProcess: The result of the execution
    """
    return subprocess.run(command, stdout=PIPE, stderr=PIPE)

def status() -> str:
    """
    Check and return the status of the linuxmuster-fileserver services.

    This function checks the status of the 'smbd' and 'winbind' services
    using systemctl and returns a string indicating whether each service
    is running or inactive.

    Returns:
        str: A string message indicating the status of the 'smbd' and 'winbind' services.
    """

    smbdstatus = __execute(["/usr/bin/systemctl", "status", "smbd"])
    winbindstatus = __execute(["/usr/bin/systemctl", "status", "winbind"])
    
    result = "\nChecking status for linuxmuster-fileserver services:\n"

    if "running" in smbdstatus.stdout.decode():
        result += "✅ smbd is up an running!\n"
    else:
        result += "❌ smbd is inactive or dead!\n"

    if "running" in winbindstatus.stdout.decode():
        result += "✅ winbind is up an running!\n"
    else:
        result += "❌ winbind is inactive or dead!\n"

    return result

def setup(domain, username, password, school) -> str:
    """
    Setup the linuxmuster-fileserver configuration and join the domain.

    This function performs several setup tasks for the linuxmuster-fileserver:
    1. Configures kerberos, nsswitch, and samba by copying template files and replacing placeholders.
    2. Joins the server to the Active Directory domain using provided credentials.
    3. Creates a new share for the specified school and configures its parameters.
    4. Initializes and enables quotas for the school's share directory.
    5. Restarts the 'smbd' and 'winbind' services to apply changes.

    Args:
        domain (str): The domain name for the fileserver (e.g., linuxmuster.lan).
        username (str): The username with join permissions.
        password (str): The password corresponding to the username.
        school (str): The school shortcut for the fileserver share.

    Returns:
        str: A message indicating successful completion of the setup process.
    """

    workgroup = domain.split(".")[0]
    print()
    print("Copy template for new krb5.conf... ", end="")
    with open("/var/lib/linuxmuster-fileserver/krb5.conf.example", "r") as f:
        content = f.read()
        content = content.replace("%%DOMAIN%%", domain)
        with open("/etc/krb5.conf", "w") as r:
            r.write(content)
    if os.path.exists("/etc/krb5.conf"):
        print("✅")
    else:
        sys.exit("❌")
    
    print("Copy template for new nsswitch.conf... ", end="")
    with open("/var/lib/linuxmuster-fileserver/nsswitch.conf.example", "r") as f:
        content = f.read()
        with open("/etc/nsswitch.conf", "w") as r:
            r.write(content)
    if os.path.exists("/etc/nsswitch.conf"):
        print("✅")
    else:
        sys.exit("❌")

    print("Copy template for new smb.conf... ", end="")
    with open("/var/lib/linuxmuster-fileserver/smb.conf.example", "r") as f:
        content = f.read()
        content = content.replace("%%DOMAIN%%", domain)
        content = content.replace("%%HOSTNAME%%", socket.gethostname().upper())
        content = content.replace("%%WORKGROUP%%", workgroup)
        with open("/etc/samba/smb.conf", "w") as r:
            r.write(content)
    if os.path.exists("/etc/samba/smb.conf"):
        print("✅")
    else:
        sys.exit("❌")

    print("Try to join domain with given data... ", end="")
    output = __execute(["/usr/bin/net", "ads", "join", "-U", username + "%" + password])
    if "Join is OK" in __execute(["/usr/bin/net", "ads", "testjoin"]).stdout.decode():
        print("✅")
    else:
        sys.exit(f"❌ \n\033[91m{output.stdout.decode()}\033[0m")

    print("Create share for school on this fileserver... ", end="")
    path = "/srv/samba/schools/" + school
    os.makedirs(path, exist_ok=True)
    __execute(["/usr/bin/net", "conf", "addshare", school, path])
    __execute(["/usr/bin/net", "conf", "setparm", school, "comment", f"Share for {school}"])
    __execute(["/usr/bin/net", "conf", "setparm", school, "valid users", f"{workgroup}\\administrator,@{workgroup}\\SCHOOLS"])
    __execute(["/usr/bin/net", "conf", "setparm", school, "read only", "no"])
    __execute(["/usr/bin/net", "conf", "setparm", school, "hide unreadable", "yes"])
    __execute(["/usr/bin/net", "conf", "setparm", school, "admin users", f"{workgroup}\\administrator"])
    __execute(["/usr/sbin/quotacheck", "-cumg", path])
    __execute(["/usr/sbin/quotaon", path])

    if school in __execute(["/usr/bin/net", "conf", "list"]).stdout.decode():
        print("✅")
    else:
        sys.exit("❌")

    print("Restart service smbd.... ", end="")
    __execute(["/usr/bin/systemctl", "restart", "smbd"])
    if "running" in __execute(["/usr/bin/systemctl", "status", "smbd"]).stdout.decode():
        print("✅")
    else:
        print("❌")

    print("Restart service winbind.... ", end="")
    __execute(["/usr/bin/systemctl", "restart", "winbind"])
    if "running" in __execute(["/usr/bin/systemctl", "status", "winbind"]).stdout.decode():
        print("✅")
    else:
        print("❌")

    return "\nSetup finished successfully!\n"

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--debug", required=False, help="Print debug output", action="store_true")

    subparsers = parser.add_subparsers(dest="command")
    parserSetup = subparsers.add_parser("setup", help="Setup a new fileserver")
    parserSetup.add_argument("-d", "--domain", required=False, help='Linuxmuster domain name (eg. linuxmuster.lan)', default="linuxmuster.lan")
    parserSetup.add_argument("-u", "--username", required=False, help='Username of user with join permissions', default="global-admin")
    parserSetup.add_argument("-p", "--password", required=False, help='Password of user with join permissions')
    parserSetup.add_argument("-s", "--school", required=False, help='Schoolshortcut for this fileserver', default="default-school")

    subparsers.add_parser("status", help="Status of caching server(s)")

    args = parser.parse_args()

    print(r"""
=======================================================================
    _     ___ _   _ _   ___  ____  __ _   _ ____ _____ _____ ____  
   | |   |_ _| \ | | | | \ \/ /  \/  | | | / ___|_   _| ____|  _ \ 
   | |    | ||  \| | | | |\  /| |\/| | | | \___ \ | | |  _| | |_) |
   | |___ | || |\  | |_| |/  \| |  | | |_| |___) || | | |___|  _ < 
   |_____|___|_| \_|\___//_/\_\_|  |_|\___/|____/ |_| |_____|_| \_\ 


   Commandline-Tool to configure and manage LINUXMUSTER-Fileserver!

=======================================================================
    """)

    if args.command == "setup":
        if not args.password:
            password = getpass("Please enter password for %s@%s: " % (args.username, args.domain.upper()))
        else:
            password = args.password
        print(setup(args.domain.upper(), args.username, password, args.school.lower()))
    elif args.command == "status":
        print(status())
    else:
        parser.print_help()



if __name__ == "__main__":
    main()
