#!python
#pylint: disable-msg=W0612

import readline
import argparse
import yaml
import os
import sys


from mbo.modules.databases.mongodb import MongoDb
from microboiler.modules.databases.mysql import Mysql
from microboiler.modules.databases.postgre import Postgre
from microboiler.modules.databases.redis import Redis

from microboiler.modules.clients.angular import Angular

from microboiler.modules.eventbus.rabbitmq import RabbitMq

from microboiler.modules.identity.identityserver4 import IdentityServer4

from microboiler.modules.services.dotnetapi import DotnetApi
from microboiler.modules.services.nodeapi import NodeApi

from microboiler.modules.servers.nginx import Nginx
from microboiler.modules.devops.docker import Docker

parser = argparse.ArgumentParser(description='Generate and start your new project from moon')
parser.add_argument('--config','-c', type=str, help='Configuration file', required=True)
parser.add_argument('--output','-o', type=str, help='Output directory', required=False)
parser.add_argument('--force','-f',type=bool)

args = vars(parser.parse_args())
configFilePath = os.path.join(os.getcwd(),args['config'])
projectOptions = {}

scriptPath = os.path.dirname(os.path.realpath(sys.argv[0]))
templatesPath = os.path.normpath(os.path.join(scriptPath,'templatefiles'))




def CreateProjectDirectory(projectName):

    project_output_dir = None
    if args['output'] is not None :
        project_output_dir = os.path.normpath(os.path.join(os.getcwd(),args['output']))
    else:
        project_output_dir = os.path.normpath(os.path.join(os.getcwd(),projectName))

    srcDir = os.path.normpath(os.path.join(project_output_dir,"src"))
    docker_volume_dir = os.path.normpath(os.path.join(project_output_dir,"docker_volumes"))
    if not os.path.isdir(srcDir):
        os.makedirs(srcDir)
    if not os.path.isdir(docker_volume_dir):
        os.makedirs(docker_volume_dir)
    # Create README.md
    f = open(os.path.normpath(os.path.join(project_output_dir,'README.md')), 'w+')
    f.write('#'+projectName)
    f.close()
    return project_output_dir, srcDir
    

def HandleServers(servers):
    print ('Configuring Servers')
    for server in servers:
        server_options = list(server.values())[0]
        print('Building'+ server_options['name'])
        if server_options['type'] == 'nginx':
            nginx_instance = Nginx(projectOptions,templatesPath,project_output_dir, server_options)
            nginx_instance.GenerateNginxInstance()


def HandleDatabases(databases):
    print ('Configuring Databases')
    for db in databases:
        db_options = list(db.values())[0]
        print('Scaffolding '+db_options['name'])
        if(db_options['type'] == 'postgresql'):
            postgre_ins = Postgre(projectOptions,templatesPath,project_output_dir)
            postgre_ins.HandlePostgre(db_options)
        if(db_options['type'] == 'mysql'):
            mysql_ins = Mysql(projectOptions,templatesPath,project_output_dir)
            mysql_ins.HandleMysql(db_options)
        elif db_options['type'] == 'redis':
            redis_ins = Redis(projectOptions,templatesPath,project_output_dir)
            redis_ins.HandleRedisDatabase(db_options)
        elif db_options['type'] == 'mongodb':
            mongo_ins = MongoDb(projectOptions,templatesPath,project_output_dir)
            mongo_ins.HandleMongoDb(db_options)


def HandleEventBus(eventbuses):
    print ('Configuring Bus Instances..')
    for evenbus in eventbuses:
        evenbus_options = list(evenbus.values())[0]
        print('Scaffolding '+evenbus_options['name'])
        if(evenbus_options['type'] == 'rabbitmq'):
            rabbit_ins = RabbitMq(projectOptions,templatesPath,project_output_dir)
            rabbit_ins.HandleRabbitMq(evenbus_options)

def HandleIdentityServices(identity_services):
    print ('Scaffolding Identity Services...')
    for i_service in identity_services:
        i_service_options = list(i_service.values())[0]
        if (i_service_options['type']=='identityserver4'):
            is4_ins = IdentityServer4(projectOptions,templatesPath,project_output_dir)
            is4_ins.HandleIdentityServer4(i_service_options)


def HandleApiServices(api_services):
    print ('Scaffolding Api Services')
    for api_service in api_services:
        api_service_options = list(api_service.values())[0]
        if(api_service_options['type']=='dotnet_web_api'):
            dotnetapi_ins = DotnetApi(projectOptions,templatesPath,project_output_dir)
            dotnetapi_ins.HandleDotnetApiService(api_service_options)
        if(api_service_options['type']=='node_web_api'):
            nodeapi_ins = NodeApi(projectOptions,templatesPath,project_output_dir)
            nodeapi_ins.HandleNodeWebApi(api_service_options)



def HandleClients(clients):
    print ('Scaffolding Clients')
    for client in clients:
        client_options = list(client.values())[0]
        if(client_options['type']=='angular_cli_6_ssr'):
            angular_ins = Angular(projectOptions,templatesPath,project_output_dir)
            angular_ins.HandleAngular6SsrClient(client_options) 



with open(configFilePath, 'r') as stream:
    try:
        # Load Yaml
        projectOptions = yaml.load(stream)
        if not ('name' in projectOptions):
            print('Please Provide a valid project name')
            exit
        projectName = projectOptions['name']
        # Create Project Files
        project_output_dir, srcDir = CreateProjectDirectory(projectName)
        # init as singleton
        dock = Docker(projectOptions,templatesPath,project_output_dir)

        # Create Servers (Nginx Apache)
        if('servers' in projectOptions):
            HandleServers(projectOptions['servers'])

        # Create Databases (Postgre, Mysql, Redis)
        if('databases' in projectOptions):
            HandleDatabases(projectOptions['databases'])
            
        # Configure Eventbus Instances (Rabbitmq)
        if('eventbus' in projectOptions):
            HandleEventBus(projectOptions['eventbus'])

        # Create and configure identity_services
        if('identity_services' in projectOptions):
            HandleIdentityServices(projectOptions['identity_services'])

        # Create and configure api_serviecs
        if('api_services' in projectOptions):
            HandleApiServices(projectOptions['api_services'])
        # Create and configure clients
        if('clients' in projectOptions):
            HandleClients(projectOptions['clients'])

        docker_compose_path = os.path.join(project_output_dir,'docker-compose.yml')
        dock.DumpTo(docker_compose_path)
        dock.DockerComposeFinalization(docker_compose_path)

        
    except yaml.YAMLError as exc:
        print('Error parsing yml document')
        print(exc)    

