import configparser
import io
import socket
import time
from configparser import ConfigParser
from sys import stdout

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


class ApplyOpsiRepositories(SetupStep):
    def _set_user_pw(self, config: ConfigParser, section):
        log(f'Reconfiguring {section}...', Severity.TRACE)
        config.set(section, 'username', self.credentials.mli)
        config.set(section, 'password', self.credentials.mli_password)

    def _is_opsiconfd_running(self) -> bool:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(1)

        try:
            sock.connect((MACHINE_COLLECTION.backup.get_hostname(), 4447))
            sock.close()
            return True
        except TimeoutError:
            return False
        except (OSError, ConnectionRefusedError):
            return False

    def run(self, file_cleanup_stack: list[FileCleanupTask], credentials: PlaybookCredentialCollection) -> bool:
        self.credentials = credentials
        log('Applying Opsi repositories...')
        backup = MACHINE_COLLECTION.backup
        server = MACHINE_COLLECTION.server

        log('Updating paedml-linux-82.repo...', Severity.DEBUG)
        paedml_linux_82_config = server.read_file('/etc/paedml-lis/paedml-linux-82.repo')
        with io.StringIO(paedml_linux_82_config.decode('utf-8')) as config_buffer:
            config = configparser.ConfigParser()
            config.read_file(config_buffer)

            self._set_user_pw(config, 'repository_paedml_gs_82')
            self._set_user_pw(config, 'repository_paedml_linux_82')
            self._set_user_pw(config, 'repository_paedml_linux_82_auto')
            self._set_user_pw(config, 'repository_paedml_linux_abo')

            config_buffer.truncate(0)
            config_buffer.seek(0)
            config.write(config_buffer)
            paedml_linux_82_config_updated = config_buffer.getvalue()
        backup.write_file('/etc/opsi/package-updater.repos.d/paedml-linux-82.repo', paedml_linux_82_config_updated)

        log('Updating paedml-opsi43.repo...', Severity.DEBUG)
        paedml_opsi43_config = server.read_file('/etc/paedml-lis/paedml-opsi43.repo')
        with io.StringIO(paedml_opsi43_config.decode('utf-8')) as config_buffer:
            config = configparser.ConfigParser()
            config.read_file(config_buffer)

            self._set_user_pw(config, 'repository_paedml_opsi43')

            config_buffer.truncate(0)
            config_buffer.seek(0)
            config.write(config_buffer)
            paedml_opsi43_config_updated = config_buffer.getvalue()
        backup.write_file('/etc/opsi/package-updater.repos.d/paedml-opsi43-config.repo', paedml_opsi43_config_updated)

        log('Cleaning up old repos...', Severity.DEBUG)
        backup.delete('/etc/opsi/package-updater.repos.d/paedml-linux-80.repo')
        backup.delete('/etc/opsi/package-updater.repos.d/paedml-opsi43.repo')

        log("Invoking opsi-set-rights...")
        backup.execute_shell_command('opsi-set-rights')

        log("Waiting for opsiconfd to become available...", Severity.DEBUG)
        while not self._is_opsiconfd_running():
            time.sleep(1)

        log("Updating opsi repositories...")
        stdout, stderr, retval = backup.execute_shell_command('opsi-package-updater', '--ignore-errors', 'update')
        if retval != 0:
            log(f'Opsi package updater was unable to update despite --ignore-errors: {stderr}', Severity.WTF)
            return False

        log('Opsi repositories have been applied.', Severity.DEBUG)
        return True