#!/usr/bin/env python
#pylint: disable-msg=W0612

import readline
import argparse
import yaml
import os
import sys

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

from modules.clients.angular import Angular

from modules.eventbus.rabbitmq import RabbitMq

from modules.identity.identityserver4 import IdentityServer4

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

from modules.servers.nginx import Nginx
from 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'])
print (args['output'])

projectOptions = {}

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

# project_templates_paths = {    
# 
#     'serversPath' : os.path.join(templatesPath,'servers'),
#     'apiServicesPath' : os.path.join(templatesPath,'api_services'),
#     'clientsPath' : os.path.join(templatesPath,'clients'),
#     'databasesPath' : os.path.join(templatesPath,'databases'),
#     'eventbusPath' : os.path.join(templatesPath,'eventbus'),
#     'identityServicesPath' : os.path.join(templatesPath,'identity_services')
# 
# }


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)    

