#!/usr/bin/env python3
import sys
import os
import json
import cmd
import mage2gen
from mage2gen import Snippet, SnippetParam
from mage2gen.utils import upperfirst
from collections import defaultdict, OrderedDict


class Mage2Gen(cmd.Cmd):
	prompt = '(Mage2Gen) '

	def __init__(self, *args, **kwargs):
		super(Mage2Gen, self).__init__(*args, **kwargs)
		self.preloop_runed = False
		self.package_name = 'Mage2gen'
		self.module_name = ''
		self.description = ''

		self._snippets = self.load_snippets()
		self._module_snippets = defaultdict(list)

	def load_snippets(self):
		snippets = {}
		for snippet in Snippet.snippets():
			snippets[snippet.name().lower()] = snippet
		return snippets

	def cmdloop(self):
		while True:
			try:
				super(Mage2Gen, self).cmdloop(intro="")
				self.postloop()
				break
			except KeyboardInterrupt as e:
				print("^C")

	def emptyline(self):
		return ''

	def do_exit(self, line):
		"""Exit mage2gen console"""
		return True

	def ask_param_input(self, param):
		default_label = ' [{}]'.format(param.default) if param.default else ''
		required = param.required

		if param.yes_no:
			required = True
			default_label = ' [Y/n]' if param.default else ' [y/N]'

		while True:
			try:
				result = input('{}{}{}: '.format(param.name_label(), default_label, '*' if param.required  else ''))
			except EOFError:
				sys.exit()

			if param.yes_no:
				if result in ['y', 'Y']:
					result = True
				elif result in ['n', 'N']:
					result = False
				elif param.default != None:
					result = param.default
				else:
					result = ''
			elif param.default != None and not result:
				result = param.default

			try:
				param.validate(result)
			except Exception as e:
				print(e)
				continue

			break

		return result


	def preloop(self):
		if not self.preloop_runed:
			self.do_edit()
			print('\nType help or ? to list commands.')
			self.preloop_runed = True

	def do_edit(self, line=None):
		"""Edit the Module package name, name and description"""
		self.package_name = self.ask_param_input(SnippetParam(name='Package name', default=self.package_name, required=True))
		self.module_name = self.ask_param_input(SnippetParam(name='Module name', default=self.module_name , required=True))
		self.description = self.ask_param_input(SnippetParam(name='Description', default=self.description , required=False))

	def do_list(self, line):
		"""List available snippets"""
		print(' '.join(self._snippets))

	def do_add(self, line):
		"""Add a snippet to module"""
		SnippetClass = self._snippets.get(line)
		if SnippetClass:
			params = OrderedDict()
			for param in SnippetClass.params():
				params[param.name] = self.ask_param_input(param)
			self._module_snippets[SnippetClass].append(params)

	def complete_add(self, text, line, begidx, endidx):
		return [s for s in self._snippets if s.startswith(text)]

	def do_remove(self, line):
		"""Remove a snippet to module"""
		args = line.split()
		if len(args) == 2:
			try:
				SnippetClass = self._snippets.get(args[0])
				self._module_snippets[SnippetClass].pop(int(args[1]))
				print('Removed {} snippet'.format(SnippetClass.name()))
				if len(self._module_snippets[SnippetClass]) == 0:
					self._module_snippets.pop(SnippetClass, None)
			except Exception:
				print('Could not remove snippet')


	def complete_remove(self, text, line, begidx, endidx):
		return [s for s in self._snippets if s.startswith(text)]

	def do_generate(self, line):
		"""Generate module"""
		module = mage2gen.Module(package=self.package_name, name=self.module_name, description=self.description)

		# snippets
		for SnippetClass, kwargss in self._module_snippets.items():
			snippet = SnippetClass(module)
			for kwargs in kwargss:
				snippet.add(**kwargs)

		# generate
		path = ''
		lookup_path = os.getcwd()
		while True:
			if lookup_path == os.path.dirname(lookup_path):
				break

			composer_path = os.path.join(lookup_path, 'composer.json')
			try:
				composer = json.loads(open(composer_path).read())
				if composer['name'] in ['magento/project-community-edition', 'magento/magento2ce']:
					path = os.path.join(lookup_path, 'app', 'code')
					break
			except Exception:
				pass

			lookup_path = os.path.dirname(lookup_path)

		path = self.ask_param_input(SnippetParam(name='Generate path', default=path, required=True))

		if not os.path.isdir(path):
			if self.ask_param_input(SnippetParam(name='Path does not exist, do you want to create it?', yes_no=True)):
				try:
					os.makedirs(path)
				except Exception:
					pass
			else:
				return
		elif os.path.isdir(os.path.join(path, module.package, module.name)):
			if self.ask_param_input(SnippetParam(name='Module {}/{} already exists in this root, do you want to rewrite this?'.format(module.package, module.name), yes_no=True)):
				return
		
		module.generate_module(path)
		print('Module ({}/{}) generated to: {}'.format(module.package, module.name, path))

	def do_info(self, line):
		"""Show current module configuration"""
		print('\n{}/{}'.format(self.package_name, self.module_name))
		for SnippetClass, kwargss in self._module_snippets.items():
			print('\n{}s\n'.format(SnippetClass.__name__.lower().replace('snippet', '').capitalize()))
			kwarg_size = {}
			for index, kwargs in enumerate(kwargss):
				for key, value in kwargs.items():
					size = len(str(value)) if len(str(value)) > len(str(key)) else len(str(key))
					if size > kwarg_size.get(key, 0):
						kwarg_size[key] = size + 2

			for index, kwargs in enumerate(kwargss):
				if index == 0:
					header = 'Index  '
					for key, value in kwargs.items():
						header += upperfirst(key.replace('_', ' ')).ljust(kwarg_size[key])
					print(header)
					total_size = sum(kwarg_size.values()) + 7
					total_size = total_size if total_size > 80 else 80
					print('-' * total_size)

				row = str(index).ljust(7)
				for key, value in kwargs.items():
					row += str(value).ljust(kwarg_size[key])
				print(row)
			print('-' * 80)
		print()


	def do_EOF(self, line):
		return True

if __name__ == '__main__':
	Mage2Gen().cmdloop()