#!/usr/bin/env python3

import os
import subprocess
import csv
from datetime import datetime

LOG_FILE = "/var/log/mspub_user_mgmt.log"
DEFAULT_PASSWORD = "Hyrul3Warr10r$"
IMPORT_CSV_FILE = "/opt/mspub-usrmgmt/batch-usr-import.csv"
REMOVE_CSV_FILE = "/opt/mspub-usrmgmt/bulk-usr-delete.csv"

def check_root():
    """Verify the script is running with root privileges."""
    if os.geteuid() != 0:
        print("The MSPUB User Management Script must be run with sudo privileges.")
        exit(1)

    log_action("Root privilege check passed.")


def log_action(message):
    """Write script activity to the log file."""
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

    with open(LOG_FILE, "a") as log:
        log.write(f"[{timestamp}] {message}\n")


def run_command(command):
    """Run a Linux command and log success or failure."""
    try:
        result = subprocess.run(
            command,
            shell=True,
            check=True,
            text=True,
            capture_output=True
        )

        log_action(f"SUCCESS: {command}")
        return result.stdout

    except subprocess.CalledProcessError as error:
        log_action(f"ERROR: {command}")
        log_action(error.stderr)
        print(f"Command failed: {command}")
        print(error.stderr)
        return None


# Group Creation
def install_default_groups():
    """Create the default MSPUB department groups."""
    print("\nInstalling MSPUB department groups...")

    groups = [
        "administration",
        "publishing",
        "it-cyber",
        "online-services"
    ]

    for group in groups:
        group_exists = subprocess.run(
            f"getent group {group}",
            shell=True,
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL
        )

        if group_exists.returncode == 0:
            print(f"Group already exists: {group}")
            log_action(f"Group already exists: {group}")
        else:
            run_command(f"groupadd {group}")
            print(f"Created group: {group}")
            log_action(f"Created group: {group}")

    print("MSPUB department groups installation complete.")


def create_custom_group():
    """Create a custom Linux group."""
    group_name = input("\nEnter custom group name: ").strip().lower()

    if not group_name:
        print("Group name cannot be blank.")
        return

    group_exists = subprocess.run(
        f"getent group {group_name}",
        shell=True,
        stdout=subprocess.DEVNULL,
        stderr=subprocess.DEVNULL
    )

    if group_exists.returncode == 0:
        print(f"Group already exists: {group_name}")
        log_action(f"Group already exists: {group_name}")
    else:
        run_command(f"groupadd {group_name}")
        print(f"Created custom group: {group_name}")
        log_action(f"Created custom group: {group_name}")


# User Creation
def create_user():
    """Create a new Linux user account and optionally assign group."""
    first_name = input("\nEnter employee first name initial: ").strip().lower()
    last_name = input("Enter employee full last name: ").strip().lower()
    group_name = input("Enter MSPUB group name for this user: ").strip().lower()

    if not first_name or not last_name:
        print("First name and last name cannot be blank.")
        return

    username = f"{first_name}.{last_name}"

    user_exists = subprocess.run(
        f"id {username}",
        shell=True,
        stdout=subprocess.DEVNULL,
        stderr=subprocess.DEVNULL
    )

    if user_exists.returncode == 0:
        print(f"User already exists: {username}")
        log_action(f"User already exists: {username}")
        return

    if group_name:
        group_exists = subprocess.run(
            f"getent group {group_name}",
            shell=True,
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL
        )

        if group_exists.returncode != 0:
            print(f"Group does not exist: {group_name}")
            create_group = input("Create this group now? (y/n): ").strip().lower()

            if create_group == "y":
                run_command(f"groupadd {group_name}")
                log_action(f"Created group during user creation: {group_name}")
            else:
                print("User creation cancelled.")
                return

        run_command(f"useradd -m -s /bin/bash -G {group_name} {username}")
        log_action(f"Created user {username} and assigned to group {group_name}")
    else:
        run_command(f"useradd -m -s /bin/bash {username}")
        log_action(f"Created user {username} without group assignment")

    password_process = subprocess.run(
        ["chpasswd"],
        input=f"{username}:{DEFAULT_PASSWORD}\n",
        text=True,
        capture_output=True
    )

    if password_process.returncode == 0:
        log_action(f"MSPUB default password assigned to {username}")
    else:
        log_action(f"Password assignment failed for {username}: {password_process.stderr}")
        print(f"Password assignment failed for {username}.")
        print(password_process.stderr)

    run_command(f"chage -d 0 {username}")
    log_action(f"Forced password change at next login for {username}")

    print(f"User created successfully: {username}")
    print(f"Temporary password: {DEFAULT_PASSWORD}")


def delete_user():
    """Delete an existing Linux user account."""
    username = input("\nEnter username to delete: ").strip().lower()

    if not username:
        print("Username cannot be blank.")
        return

    user_exists = subprocess.run(
        f"id {username}",
        shell=True,
        stdout=subprocess.DEVNULL,
        stderr=subprocess.DEVNULL
    )

    if user_exists.returncode != 0:
        print(f"User does not exist: {username}")
        log_action(f"Delete failed. User does not exist: {username}")
        return

    confirm = input(f"Are you sure you want to delete {username}? (y/n): ").strip().lower()

    if confirm == "y":
        run_command(f"userdel -r {username}")
        print(f"Deleted user: {username}")
        log_action(f"Deleted user: {username}")
    else:
        print("User deletion cancelled.")
        log_action(f"User deletion cancelled for {username}")


def prepare_batch_csv_file():
    """Create the batch import CSV file if it does not already exist"""

    csv_dir = "/opt/mspub-usrmgmt/"

    if not os.path.exists(csv_dir):
        run_command (f"mkdir -p {csv_dir}")

    if not os.path.exists(IMPORT_CSV_FILE):
        sample_content = """first_name,last_name,group_name
l,hero,publishing
z,princess,administration
s,zora,publishing
"""

        with open(IMPORT_CSV_FILE, "w") as file:
            file.write(sample_content)

            run_command(f"chmod 664 {IMPORT_CSV_FILE}")
            log_action(f"Created sample batch import CSV file: {IMPORT_CSV_FILE}")

def batch_user_import():
    """Create multiple users from a static CSV file."""

    prepare_batch_csv_file()

    print("\nBulk User Import")
    print("-" * 40)
    print(f"CSV file location: {IMPORT_CSV_FILE}")
    print("\nInstructions:")
    print("1. Open the CSV file in a text editor.")
    print("2. Add one user per line using this format: ")
    print("      first_name,last_name,group_name")
    print("       per the MSPUB naming convention for usernames first_name = first initial dot last_name = full last name. E.g. p.sheikah")
    print("3. Save the CSV file before continuing.")
    print("4. Existing users will be skipped.")
    print("5. Missing groups will be created automatically.")
    print("\nCSV file Example:")
    print("        r,sheikah,it-cyber")
    print("        l,hero,it-cyber")
    print("         z,princess,administration")

    confirm = input("\nReady to begin the import? (y/n): ").strip().lower()

    if confirm != "y":
        print("Batch import cancelled.")
        log_action("Batch import cancelled by administrator.")
        return

    with open(IMPORT_CSV_FILE, "r") as csv_file:
        reader = csv.DictReader(csv_file)

        for row in reader:
            first_name = row["first_name"].strip().lower()
            last_name = row["last_name"].strip().lower()
            group_name = row["group_name"].strip().lower()

            if not first_name or not last_name or not group_name:
                log_action("Batch import skipped incomplete row.")
                continue

            username = f"{first_name}.{last_name}"

            user_exists = subprocess.run(
                f"id {username}",
                shell=True,
                stdout=subprocess.DEVNULL,
                stderr=subprocess.DEVNULL
            )

            if user_exists.returncode == 0:
                print(f"User already exists, skipped: {username}")
                log_action(f"Batch import skipped existing user: {username}")
                continue

            group_exists = subprocess.run(
                f"getent group {group_name}",
                shell=True,
                stdout=subprocess.DEVNULL,
                stderr=subprocess.DEVNULL
            )

            if group_exists.returncode != 0:
                run_command(f"groupadd {group_name}")
                log_action(f"Batch import created group: {group_name}")

            run_command(f"useradd -m -s /bin/bash -G {group_name} {username}")

            password_process = subprocess.run(
                ["chpasswd"],
                input=f"{username}:{DEFAULT_PASSWORD}\n",
                text=True,
                capture_output=True
            )

            if password_process.returncode == 0:
                log_action(f"Batch import assigned default password to {username}")
            else:
                log_action(f"Batch import password assignment failed for {username}: {password_process.stderr}")
                print(f"Password assignment failed for {username}")

            run_command(f"chage -d 0 {username}")

            print(f"Created user: {username}")
            log_action(f"Batch import created user {username} in group {group_name}. Default password set. Change password next logon: TRUE")

    print("Batch user import completed.")
    log_action("Batch user import completed.")

# Assignment
def assign_user_group():
    """Assign an existing user to an existing group."""
    username = input("\nEnter username: ").strip().lower()
    group_name = input("Enter group name: ").strip().lower()

    if not username or not group_name:
        print("Username and group name cannot be blank.")
        return

    user_exists = subprocess.run(
        f"id {username}",
        shell=True,
        stdout=subprocess.DEVNULL,
        stderr=subprocess.DEVNULL
    )

    if user_exists.returncode != 0:
        print(f"User does not exist: {username}")
        log_action(f"Group assignment failed. User does not exist: {username}")
        return

    group_exists = subprocess.run(
        f"getent group {group_name}",
        shell=True,
        stdout=subprocess.DEVNULL,
        stderr=subprocess.DEVNULL
    )

    if group_exists.returncode != 0:
        print(f"Group does not exist: {group_name}")
        log_action(f"Group assignment failed. Group does not exist: {group_name}")
        return

    run_command(f"usermod -aG {group_name} {username}")

    print(f"Added {username} to {group_name}")
    log_action(f"Added {username} to group {group_name}")


def force_password_change():
    """Force a user to change their password at next login."""
    username = input("\nEnter username: ").strip().lower()

    if not username:
        print("Username cannot be blank.")
        return

    user_exists = subprocess.run(
        f"id {username}",
        shell=True,
        stdout=subprocess.DEVNULL,
        stderr=subprocess.DEVNULL
    )

    if user_exists.returncode != 0:
        print(f"User does not exist: {username}")
        log_action(f"Password reset failed. User does not exist: {username}")
        return

    run_command(f"chage -d 0 {username}")

    print(f"Password change required for {username}")
    log_action(f"Forced password change for {username}")


# Other Features
def list_users():
    """Display local users with home directories."""
    print("\nMSPUB User Accounts")
    print("-" * 40)

    try:
        with open("/etc/passwd", "r") as passwd_file:
            for line in passwd_file:
                fields = line.split(":")

                username = fields[0]
                uid = int(fields[2])
                home = fields[5]

                if uid >= 1000 and home.startswith("/home"):
                    print(username)

        log_action("Displayed user list.")

    except Exception as error:
        print(f"Error displaying users: {error}")
        log_action(f"Error displaying users: {error}")

def prepare_remove_csv_file():
    """Create teh batch user removal CSV file if it does not already exist."""

    csv_dir = "/opt/mspub-usrmgmt/"

    if not os.path.exists(csv_dir):
        run_command(f"mkdir -p {csv_dir}")

    if not os.path.exists(REMOVE_CSV_FILE):
        sample_content = """username
z.princess
i.sheikah
p.sheikah
"""
        with open(REMOVE_CSV_FILE, "w") as file:
            file.write(sample_content)

        run_command(f"chmod 644 {REMOVE_CSV_FILE}")
        log_action(f"Created sample batch removal CSV file: {REMOVE_CSV_FILE}")

def bulk_delete_users():
    """Delete multiple users from a static CSC file."""

    prepare_remove_csv_file()

    print("\nBulk User Deletion")
    print("-" * 40)
    print(f"CSV file location: {REMOVE_CSV_FILE}")
    print("\nInstructions:")
    print("1. Open the CSV file in a text editor.")
    print("2. Add one user per line using this format:")
    print("      username")
    print("3. Save the CSV file before continuing.")
    print("4. User listed in the file will be deleted with their home directories.")
    print("\nExample:")
    print("      z.princess")
    print("      i.sheikah")

    confirm = input("\nAre you sure you want to delete all users listed in this file? (y/n): ").strip().lower()

    if confirm !="y":
        print("Bulk user deletion cancelled.")
        log_action("Bulk user deletion cancelled by administrator.")
        return

    with open(REMOVE_CSV_FILE, "r") as csv_file:
        reader = csv.DictReader(csv_file)

        for row in reader:
            username = row["username"].strip().lower()

            if not username:
                log_action("Bulk delete dkipped blank username row.")
                continue

            user_exists = subprocess.run(
                f"id {username}",
                shell=True,
                stdout=subprocess.DEVNULL,
                stderr=subprocess.DEVNULL
            )

            if user_exists.returncode != 0:
                print(f"User does not exist, skipped: {username}")
                log_action(f"Bulk delte skipped missing user: {username}")
                continue

            run_command(f"userdel -r {username}")
            log_action(f"Bulk delete removed user: {username}")
    
    print("Bulk user deletion completed.")
    print("Returning to main menu.")
    log_action("Bulk user deletion completed.")

# Menu
def display_menu():
    print(r"""
        <==================================================>
        | |                                          /\
        | |      MSPUB USER MANAGEMENT SYSTEM       /__\
        | |                                        /_\/_\
        <==================================================>

        Options:
        --------------------------------------------
        1. Install MSPUB Department Groups
        2. Create Custom Group
        3. Create New User
        4. Delete Existing User
        5. Assign User to Group
        6. Force Password Change
        7. List Users
        8. Bulk User Import from CSV
        9. Bulk User Deletion from CSV

        X. Exit
    """)


def main():
    check_root()

    while True:
        display_menu()
        choice = input("Select an option: ").strip().lower()

        if choice == "1":
            install_default_groups()
        elif choice == "2":
            create_custom_group()
        elif choice == "3":
            create_user()
        elif choice == "4":
            delete_user()
        elif choice == "5":
            assign_user_group()
        elif choice == "6":
            force_password_change()
        elif choice == "7":
            list_users()
        elif choice == "8":
            batch_user_import()
        elif choice == "9":
            bulk_delete_users()
        elif choice == "x":
            print("Exiting MSPUB User Management System.")
            log_action("Exited MSPUB User Management System.")
            break
        else:
            print("Invalid option. Please enter a valid option.")


if __name__ == "__main__":
    main()
