#!/usr/bin/env python
# -*- coding: utf-8 -*-

""" License
    Copyright (C) 2013 YunoHost
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published
    by the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.
    You should have received a copy of the GNU Affero General Public License
    along with this program; if not, see http://www.gnu.org/licenses
"""

"""
    Generate JSON specification files API
"""
import os
import sys
import yaml
import json
import requests

def main():
    """
    """
    with open('../share/actionsmap.yml') as f:
        action_map = yaml.safe_load(f)

    try:
        with open('/etc/yunohost/current_host', 'r') as f:
            domain = f.readline().rstrip()
    except IOError:
        domain = requests.get('http://ip.yunohost.org').text
    with open('../debian/changelog') as f:
        top_changelog = f.readline()
    api_version = top_changelog[top_changelog.find("(")+1:top_changelog.find(")")]

    csrf = {
        'name': 'X-Requested-With',
        'in': 'header',
        'required': True,
        'schema': {
            'type': 'string',
            'default': 'Swagger API'
        }

    }

    resource_list = {
        'openapi': '3.0.3',
        'info': {
            'title': 'YunoHost API',
            'description': 'This is the YunoHost API used on all YunoHost instances. This API is essentially used by YunoHost Webadmin.',
            'version': api_version,

        },
        'servers': [
            {
                'url': "https://{domain}/yunohost/api",
                'variables': {
                    'domain': {
                        'default': 'demo.yunohost.org',
                        'description': 'Your yunohost domain'
                    }
                }
            }
        ],
        'tags': [
            {
                'name': 'public',
                'description': 'Public route'
            }
        ],
        'paths': {
            '/login': {
                'post': {
                    'tags': ['public'],
                    'summary': 'Logs in and returns the authentication cookie',
                    'parameters': [csrf],
                    'requestBody': {
                        'required': True,
                        'content': {
                            'multipart/form-data': {
                                'schema': {
                                    'type': 'object',
                                    'properties': {
                                        'credentials': {
                                            'type': 'string',
                                            'format': 'password'
                                        }
                                    },
                                    'required': [
                                        'credentials'
                                    ]
                                }
                            }
                        }
                    },
                    'security': [],
                    'responses': {
                        '200': {
                            'description': 'Successfully login',
                            'headers': {
                                'Set-Cookie': {
                                    'schema': {
                                        'type': 'string'
                                    }
                                }
                            }
                        }
                    }
                }
            },
            '/installed': {
                'get': {
                    'tags': ['public'],
                    'summary': 'Test if the API is working',
                    'parameters': [],
                    'security': [],
                    'responses': {
                        '200': {
                            'description': 'Successfully working',
                        }
                    }
                }
            }
        },
    }


    def convert_categories(categories, parent_category=""):
        for category, category_params in categories.items():
            if parent_category:
                category = f"{parent_category} {category}"
            if 'subcategory_help' in category_params:
                category_params['category_help'] = category_params['subcategory_help']

            if 'category_help' not in category_params:
                category_params['category_help'] = ''
            resource_list['tags'].append({
                'name': category,
                'description': category_params['category_help']
            })


            for action, action_params in category_params['actions'].items():
                if 'action_help' not in action_params:
                    action_params['action_help'] = ''
                if 'api' not in action_params:
                    continue
                if not isinstance(action_params['api'], list):
                    action_params['api'] = [action_params['api']]

                for i, api in enumerate(action_params['api']):
                    print(api)
                    method, path = api.split(' ')
                    method = method.lower()
                    key_param = ''
                    if '{' in path:
                        key_param = path[path.find("{")+1:path.find("}")]
                    resource_list['paths'].setdefault(path, {})

                    notes = ''

                    operationId = f"{category}_{action}"
                    if i > 0:
                        operationId += f"_{i}"
                    operation = {
                        'tags': [category],
                        'operationId': operationId,
                        'summary': action_params['action_help'],
                        'description': notes,
                        'responses': {
                            '200': {
                                'description': 'successful operation'
                            }
                        }
                    }
                    if action_params.get('deprecated'):
                        operation['deprecated'] = True

                    operation['parameters'] = []
                    if method == 'post':
                        operation['parameters'] = [csrf]

                    if 'arguments' in action_params:
                        if method in ['put', 'post', 'patch']:
                            operation['requestBody'] = {
                                'required': True,
                                'content': {
                                    'multipart/form-data': {
                                        'schema': {
                                            'type': 'object',
                                            'properties': {
                                            },
                                            'required': []
                                        }
                                    }
                                }
                            }
                        for arg_name, arg_params in action_params['arguments'].items():
                            if 'help' not in arg_params:
                                arg_params['help'] = ''
                            param_type = 'query'
                            allow_multiple = False
                            required = True
                            allowable_values = None
                            name = str(arg_name).replace('-', '_')
                            if name[0] == '_':
                                required = False
                                if 'full' in arg_params:
                                    name = arg_params['full'][2:]
                                else:
                                    name = name[2:]
                                name = name.replace('-', '_')

                            if 'choices' in arg_params:
                                allowable_values = arg_params['choices']
                            _type = 'string'
                            if 'type' in arg_params:
                                types = {
                                    'open': 'file',
                                    'int': 'int'
                                }
                                _type = types[arg_params['type']]
                            if 'action' in arg_params and arg_params['action'] == 'store_true':
                                _type = 'boolean'

                            if 'nargs' in arg_params:
                                if arg_params['nargs'] == '*':
                                    allow_multiple = True
                                    required = False
                                    _type = 'array'
                                if arg_params['nargs'] == '+':
                                    allow_multiple = True
                                    required = True
                                    _type = 'array'
                                if arg_params['nargs'] == '?':
                                    allow_multiple = False
                                    required = False
                            else:
                                allow_multiple = False


                            if name == key_param:
                                param_type = 'path'
                                required = True
                                allow_multiple = False

                            if method in ['put', 'post', 'patch']:
                                schema = operation['requestBody']['content']['multipart/form-data']['schema']
                                schema['properties'][name] = {
                                    'type': _type,
                                    'description': arg_params['help']
                                }
                                if required:
                                    schema['required'].append(name)
                                prop_schema = schema['properties'][name]
                            else:
                                parameters = {
                                    'name': name,
                                    'in': param_type,
                                    'description': arg_params['help'],
                                    'required': required,
                                    'schema': {
                                        'type': _type,
                                    },
                                    'explode': allow_multiple
                                }
                                prop_schema = parameters['schema']
                                operation['parameters'].append(parameters)

                            if allowable_values is not None:
                                prop_schema['enum'] = allowable_values
                            if 'default' in arg_params:
                                prop_schema['default'] = arg_params['default']
                            if arg_params.get('metavar') == 'PASSWORD':
                                prop_schema['format'] = 'password'
                            if arg_params.get('metavar') == 'MAIL':
                                prop_schema['format'] = 'mail'
                            # Those lines seems to slow swagger ui too much
                            #if 'pattern' in arg_params.get('extra', {}):
                            #    prop_schema['pattern'] = arg_params['extra']['pattern'][0]



                    resource_list['paths'][path][method.lower()] = operation

            # Includes subcategories
            if 'subcategories' in category_params:
                convert_categories(category_params['subcategories'], category)

    del action_map['_global']
    convert_categories(action_map)

    openapi_json = json.dumps(resource_list)
    # Save the OpenAPI json
    with open(os.getcwd() + '/openapi.json', 'w') as f:
        f.write(openapi_json)

    openapi_js = f"var openapiJSON = {openapi_json}"
    with open(os.getcwd() + '/openapi.js', 'w') as f:
        f.write(openapi_js)



if __name__ == '__main__':
    sys.exit(main())