#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# Univention Management Console module:
#  System Diagnosis UMC module
#
# Copyright 2014-2021 Univention GmbH
#
# https://www.univention.de/
#
# All rights reserved.
#
# The source code of this program is made available
# under the terms of the GNU Affero General Public License version 3
# (GNU AGPL V3) as published by the Free Software Foundation.
#
# Binary versions of this program provided by Univention to you as
# well as other copyrighted, protected or trademarked materials like
# Logos, graphics, fonts, specific documentations and configurations,
# cryptographic keys etc. are subject to a license agreement between
# you and Univention and not subject to the GNU AGPL V3.
#
# In the case you use this program under the terms of the GNU AGPL V3,
# the program is provided in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License with the Debian GNU/Linux or Univention distribution in file
# /usr/share/common-licenses/AGPL-3; if not, seGe
# <https://www.gnu.org/licenses/>.

import sys
import time
import argparse
import traceback
from getpass import getpass
from six.moves import input

from univention.lib.umc import Client, Unauthorized


class CLIClient(object):

	@classmethod
	def main(cls):
		parser = argparse.ArgumentParser(description='Executes the diagnostic module checks', add_help=False)
		parser.add_argument('-h', '--help', action='store_true', help='show this help message and exit')
		parser.add_argument("--bindpwdfile", help='Path to a file that contains your password')
		parser.add_argument("--username", help='Domain Admin username for Authentication')
		args = parser.parse_known_args()[0]

		list_choices = ['all', 'list']
		parser.add_argument(
			"-t", dest='tests', choices=list_choices, nargs='+',
			default='all', help='''Choose tests to run by using `-t
			<testname>`, where <testname> can be any of the tests
			from `-t list` or run `-t all` to execute all
			diagnostic checks''')

		if args.help:
			parser.print_help()
			sys.exit(0)

		if not args.username:
			args.username = input('Domain Admin Login: ')
		args.password = None
		if args.bindpwdfile:
			with open(args.bindpwdfile) as fd:
				args.password = fd.read().strip()
		if not args.password:
			args.password = getpass('Password: ')

		try:
			client = Client(None, args.username, args.password)
		except Unauthorized as exc:
			parser.error('Login failed: %s' % (exc.message,))

		plugins = [plugin['id'] for plugin in client.umc_command('diagnostic/query').result]
		list_choices += plugins

		args = parser.parse_args()

		if 'list' in args.tests:
			print("\n\t".join(['Available tests:'] + plugins))
			sys.exit(0)

		if 'all' in args.tests:
			args.tests = plugins

		return cls(client, args).run()

	def __init__(self, client, args):
		self.client = client
		self.args = args

	def run(self):
		responses = self.run_diagnostic_checks(self.args.tests)

		exit_code = 0
		print('\nYou can find the logging messages of the diagnostic modules at /var/log/univention/management-console-module-diagnostic.log\n')
		for plugin, result in sorted(responses.items()):
			if result['type'] == 'success':
				print('ran %s successfully.\n' % (plugin,))
			else:
				exit_code = 2
				title = '## Check failed: %s - %s ##' % (plugin, result['title'])
				print('\n'.join([
					(' Start %s ' % (plugin,)).center(len(title), '#'),
					title,
					result['description'].strip(),
					(' End %s ' % (plugin,)).center(len(title), '#'),
					'',
				]))
		return exit_code

	def run_diagnostic_checks(self, plugins):
		execution = {}
		response = {}
		for plugin in plugins:
			execution[plugin] = self.client.umc_command('diagnostic/run', {'plugin': plugin}).result

		while len(execution) > len(response):
			for plugin, progress in execution.items():
				if plugin in response:
					continue
				try:
					result = self.client.umc_command('diagnostic/progress', {'progress_id': progress['id']}).result
				except Exception:
					result = {'finished': True, 'result': {'type': 'traceback', 'title': plugin, 'description': traceback.format_exc()}}

				if result['finished']:
					response[plugin] = {
						'type': result['result']['type'],
						'title': result['result']['title'],
						'description': result['result']['description'],
					}
			time.sleep(0.25)
		return response


if __name__ == '__main__':
	sys.exit(CLIClient.main())
