#!/usr/bin/env python


import readline
import argparse
import yaml
import os
import sys
from distutils.sysconfig import get_python_lib
 
from microboiler.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 path', required=True)
parser.add_argument('--output','-o', type=str, help='Output directory', required=False)
parser.add_argument('--force','-f',type=bool)
parser.add_argument('--test','-t',type=bool)

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


scriptPath = os.path.dirname(os.path.realpath(sys.argv[0]))
site_package_path = get_python_lib()

projectOptions = None
with open(configFilePath, 'r') as stream:
    try:
        # Load Yaml
        projectOptions = yaml.load(stream)
    except yaml.YAMLError as exc:
        print('Error parsing yml document')
        print(exc)   

templatesPath = None
if args['test'] is True:
    templatesPath = os.path.normpath(os.path.join(scriptPath,'templatefiles'))
else:
    templatesPath = os.path.normpath(os.path.join(site_package_path,'microboiler', 'templatefiles'))


project_output_dir = None

def CreateProjectDirectory(projectName):

    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(configFilePath,'../',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
    AddRootReadme(projectName)
    return project_output_dir, srcDir
    
def AddRootReadme(projectName):
    f = open(os.path.normpath(os.path.join(project_output_dir,'README.md')), 'w+')
    f.write('# '+projectName)
    f.close()

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) 




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)

        
     

