from .types_mgr import types
from .format import console
import re


class ArgsProcessing:
	def __init__(self, entry_args, commands_args, config, command_return):
		self.entry_args = entry_args
		self.commands_args = commands_args
		self._config = config
		self.command_return = command_return
		
		self.args_config = self.check_keys()
		self._check = None

		for i, arg_name in enumerate(commands_args):
			try:
				res = self.check_type(self.commands_args[arg_name], self.entry_args[i])
				if res != None:
					self._check = res
					return
			except IndexError: pass

			if self.args_config[arg_name]['default']:
				try:
					res = self.check_default(self.commands_args[arg_name], self.entry_args[i])
					if res != None:
						self._check = res
						return
				except IndexError: pass

			if self.args_config[arg_name]['allowed']:
				try:
					res = self.check_allowed(self.commands_args[arg_name], self.entry_args[i])
					if res != None:
						self._check = res
						return
				except IndexError: pass

			if self.args_config[arg_name]['pattern']:
				try:
					res = self.check_pattern(self.commands_args[arg_name], self.entry_args[i])
					if res != None:
						self._check = res
						return
				except IndexError: pass

		self._result = self.args_convert()


	@property
	def check(self):
		return self._check

	@property
	def result(self):
		return self._result


	def check_keys(self):
		args_config = {}

		for i, arg_name in enumerate(self.commands_args):
			args_config[arg_name] = {
				'allowed': 	False,
				'default': 	False,
				'pattern': 	False
			}
			if isinstance(self.commands_args, list):
				c = {}
				for arg_name in self.commands_args:
					c[arg_name] = {"type": "str"}

				self.commands_args = c.copy()

				return args_config

			if 'type' not in self.commands_args[arg_name]:
				return console(f"Type of {arg_name} is missing !", self._config, 'errors')

			if 'allowed' in self.commands_args[arg_name]:
				args_config[arg_name]['allowed'] = True

			if 'default' in self.commands_args[arg_name]:
				args_config[arg_name]['default'] = True

			if 'pattern' in self.commands_args[arg_name]:
				args_config[arg_name]['pattern'] = True

		return args_config


	def check_type(self, command_arg, entry_arg):
		# check if all types are supported
		arg_type = command_arg['type']
		if arg_type not in types:
			return console(f"Type {arg_type} is not allowed !", self._config, 'errors')

		try:
			types[arg_type][0](entry_arg)

		except TypeError:
			return console(f"{entry_arg!r} need to be type {command_arg} !", self._config, 'errors')

		# type pattern matching
		if not types[arg_type][1].match(entry_arg) and self._config['use_quotes_for_str']:
			return console(f"{entry_arg!r} type does not match required arg type {arg_type}", self._config, 'errors')


	def check_allowed(self, command_arg, entry_arg):
		arg = entry_arg.replace('"', '').replace("'", '')
		allowed = command_arg['allowed']

		if isinstance(allowed, list):
			if arg not in allowed:
				return console(f"argument {arg!r} not allowed !", self._config, 'errors')

		elif isinstance(allowed, str):
			if arg != allowed:
				return console(f"argument {arg!r} not allowed !", self._config, 'errors')

		else:
			return console("type of command_arg['allowed'] need to be str or list", self._config, 'errors')


	def check_default(self, command_arg, entry_arg):
		arg = entry_arg.replace('"', '').replace("'", '')
		default = command_arg['default']

		if not isinstance(default, str):
			return console(f"default arg: {repr(default)} need to be str", self._config, 'errors')


	def check_pattern(self, command_arg, entry_arg):
		if not isinstance(command_arg['pattern'], str):
			return console("type of command_arg['pattern'] need to be str", self._config, 'errors')

		condition = [
			not command_arg['pattern'].startswith('^'),
			not command_arg['pattern'].endswith('$'),
			self._config['pattern_full_match']
		]
		e = entry_arg.replace('"', '').replace("'", '')

		if False not in condition:
			pattern = '^' + command_arg['pattern'] + '$'
		else:
			pattern = command_arg['pattern']

		if re.findall(pattern, e) == []:
			return console(f"{e!r} does not match required pattern '{pattern}'", self._config, 'errors')


	def args_convert(self):
		for i, arg_name in enumerate(self.commands_args):
			_type = self.commands_args[arg_name]['type']

			try:

				if types[_type][0] == 'spe':
					self.command_return = self.command_return.replace(
						f'args[{arg_name}]',
						self.entry_args[i])

					continue

				# check args types and change 'args[index]' to its value
				try:
					self.command_return = self.command_return.replace(
						f'args[{arg_name}]',
						str(types[_type][0](self.entry_args[i])))	# types[_type][0] is a python type like _type: "str" -> <class 'str'>
						# converting self.entry_args[i] to this type

				except TypeError:
					return console(f"{self.entry_args[i]!r} need to be type {_type} !", self._config, 'errors')

			except IndexError:
				if not self.args_config[arg_name]['default']:
					return console(f"argument {arg_name!r} is missing !", self._config, 'errors')
			
				self.command_return = self.command_return.replace(
					f'args[{arg_name}]',
					str(repr(types[_type][0](self.commands_args[arg_name]['default']))))
		return self.command_return