import random
import secrets
import string

from ...Machine.PaedMLMachineCollection import MACHINE_COLLECTION
from ...Logging.Logger import Severity, log
from ..Playbooks.Playbook import FileCleanupTask, PlaybookCredentialCollection
from ...SetupSteps.SetupStep import SetupStep

class PermissionSettingError(Exception):
    pass

class RegenerateSslCerts(SetupStep):
    def generate_ca_id(self):
        length = 8
        characters = string.ascii_letters + string.digits
        id = ''.join(secrets.choice(characters) for i in range(length))
        return id

    def replace_ca_id(self):
        profile = MACHINE_COLLECTION.server.read_file('/var/cache/univention-system-setup/profile').decode('utf-8')
        new_profile_entries = []
        for line in profile.splitlines():
            if not line.startswith('ssl/common='):
                new_profile_entries.append(line)

        new_profile_entries.append(f'ssl/common="paed.ML Linux Root CA (ID={self.generate_ca_id()})"')
        new_profile = '\n'.join(new_profile_entries)
        MACHINE_COLLECTION.server.write_file('/var/cache/univention-system-setup/profile', new_profile.encode('utf-8'))

    def set_permissions(self, path: str, permissions: str):
        log(f'Setting permissions for {path} to {permissions}...', Severity.TRACE)
        stdout, stderr, retval = MACHINE_COLLECTION.server.execute_shell_command('chmod', permissions, path)
        if retval != 0:
            log(f'Error setting permissions for {path}: {stderr}', Severity.ERROR)
            raise PermissionSettingError

    def run(self, file_cleanup_stack: list[FileCleanupTask], credentials: PlaybookCredentialCollection) -> bool:
        log('Regenerating SSL certificates...', Severity.INFO)
        log('Replacing common name in univention profile...', Severity.DEBUG)
        self.replace_ca_id()
        log('Running ssl setup script...', Severity.DEBUG)
        stdout, stderr, retval = MACHINE_COLLECTION.server.execute_shell_command('/usr/lib/univention-system-setup/scripts/40_ssl/10ssl', '--force-recreate')

        if retval != 0:
            log(f'SSL setup script failed: {stderr if len(stderr) > 0 else stdout}', Severity.ERROR)
            return False

        log('Fixing permissions...', Severity.DEBUG)
        permission_requirements = {
            '/etc/univention/ssl': '755',
            '/etc/univention/ssl/login.paedml-linux.lokal/private.key': '750'
        }
        try:
            for (path, permissions) in permission_requirements.items():
                self.set_permissions(path, permissions)
        except PermissionSettingError:
            return False

        log(f'Setting ownership of /etc/univention/ssl/{MACHINE_COLLECTION.server.get_hostname()}...', Severity.DEBUG)
        stdout, stderr, retval = MACHINE_COLLECTION.server.execute_shell_command('chown', 'server$:DC Backup Hosts', f'/etc/univention/ssl/{MACHINE_COLLECTION.server.get_hostname()}')

        if retval != 0:
            log(f'Unable to change ownership of /etc/univention/ssl/{MACHINE_COLLECTION.server.get_hostname()}: {stderr}', Severity.ERROR)
            return False

        log('Finished regenerating SSL certificates.', Severity.DEBUG)
        return True