#!/usr/bin/env python

import os
import argparse
import itertools
from libcst import *


class DomainDefinitionInserter(CSTTransformer):
    def __init__(self, resource):
        self.resource = resource

    def leave_Module(self, original_node, updated_node):
        addition = SimpleStatementLine(
            body=[
                ImportFrom(
                    module=None,
                    names=[
                        ImportAlias(
                            name=Name(
                                value=f'{self.resource}',
                                lpar=[],
                                rpar=[],
                            ),
                            asname=None,
                            comma=MaybeSentinel.DEFAULT,
                        ),
                    ],
                    relative=[
                        Dot(
                            whitespace_before=SimpleWhitespace(
                                value='',
                            ),
                            whitespace_after=SimpleWhitespace(
                                value='',
                            ),
                        ),
                    ],
                    lpar=None,
                    rpar=None,
                    semicolon=MaybeSentinel.DEFAULT,
                    whitespace_after_from=SimpleWhitespace(
                        value=' ',
                    ),
                    whitespace_before_import=SimpleWhitespace(
                        value=' ',
                    ),
                    whitespace_after_import=SimpleWhitespace(
                        value=' ',
                    ),
                ),
            ],
            leading_lines=[],
            trailing_whitespace=TrailingWhitespace(
                whitespace=SimpleWhitespace(
                    value='',
                ),
                comment=None,
                newline=Newline(
                    value=None,
                ),
            ),
        )
        
        new_body = []
        for item in itertools.chain([updated_node.body[0], addition], updated_node.body[1:]):
            new_body.append(item)
        
        return updated_node.with_changes(
            body = new_body
        )
        
    def visit_SimpleStatementLine(self, node):
        if not isinstance(node.body[0], Assign):
            return False
            
        if not node.body[0].targets[0].target.value == 'DOMAIN_DEFINITIONS':
            return False
            
        return True

        
    def leave_Dict(self, original_node, updated_node):
        key = SimpleString(
            value=f"'{self.resource}'",
            lpar=[],
            rpar=[],
        )
        
        value = Attribute(
            value=Name(
                value=f'{self.resource}',
                lpar=[],
                rpar=[],
            ),
            attr=Name(
                value='DEFINITION',
                lpar=[],
                rpar=[],
            ),
            dot=Dot(
                whitespace_before=SimpleWhitespace(
                    value='',
                ),
                whitespace_after=SimpleWhitespace(
                    value='',
                ),
            ),
            lpar=[],
            rpar=[],
        )
        
        comma = Comma(
            whitespace_before=SimpleWhitespace(
                value='',
            ),
            whitespace_after=ParenthesizedWhitespace(
                first_line=TrailingWhitespace(
                    whitespace=SimpleWhitespace(
                        value='',
                    ),
                    comment=None,
                    newline=Newline(
                        value=None,
                    ),
                ),
                empty_lines=[],
                indent=True,
                last_line=SimpleWhitespace(
                    value='    ',
                ),
            ),
        )        
        
        addition = DictElement(key, value)
        
        new_elements = []
        last_element = updated_node.elements[-1].with_changes(comma=comma)
        
        for item in itertools.chain(updated_node.elements[0:-1], [last_element, addition]):
            new_elements.append(item)
            
        return updated_node.with_changes(
            # elements = sorted(new_elements, key=lambda i:i.key.value)
            elements = new_elements
        )


def create_resource_file(resource, add_common):
    with open(f'domain/{resource}.py', 'w') as file:
        file.write(f'''"""
Defines the {resource} resource.
"""
''')

        if add_common:
            file.write('from domain.common import COMMON_FIELDS\n\n\n')

        file.write('''SCHEMA = {
    'name': {
        'type': 'string',
        'required': True,
        'empty': False,
        'unique': True
    },
    'description': {
        'type': 'string'
    }
}

''')

        if add_common:
            file.write('SCHEMA.update(COMMON_FIELDS)\n\n')

        file.write('''DEFINITION = {
    'schema': SCHEMA,
    'datasource': {
        'projection': {'_role': 0, '_acl': 0}
    },
    'additional_lookup': {
        'url': 'regex("[\w]+")',  # pylint: disable=anomalous-backslash-in-string
        'field': 'name',
    }
}
''')


def insert_domain_definition(resource):
    with open('domain/__init__.py', 'r') as source:
        tree = parse_module(source.read())
    
    inserter = DomainDefinitionInserter(resource)
    new_tree = tree.visit(inserter)
    
    with open('domain/__init__.py', 'w') as source:
        source.write(new_tree.code)


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('resource', help='The name of the resource to create.')
    parser.add_argument('-c', '--no_common', help='Do not add common fields to this resource', action='store_true', default=False)

    args = parser.parse_args()
    resource = args.resource  # TODO: validate, safe name, etc.
    add_common = not args.no_common 

    if os.path.exists('eve_service.py') and os.path.exists('domain'):
        print(f'Creating {resource} resource')
        create_resource_file(resource, add_common)
        insert_domain_definition(resource)


if __name__ == '__main__':
    main()
