# AUTOGENERATED! DO NOT EDIT! File to edit: nbs/02-spec-gen.ipynb (unless otherwise specified).

__all__ = ['init_spec', 'load_endpoints_df', 'get_endpoint_single_attr', 'init_stream_dict',
           'add_params_to_stream_dict', 'add_streams_to_spec', 'construct_spec', 'save_spec', 'load_API_yaml']

# Cell
import numpy as np
import pandas as pd

import os
import yaml

from jinja2 import Template

# Cell
def init_spec(
    title='BMRS API',
    description='API for the Elexon Balancing Mechanism Reporting Service',
    root_url='https://api.bmreports.com'
):
    API_spec = dict()

    API_spec['title'] = title
    API_spec['description'] = description
    API_spec['root_url'] = root_url

    return API_spec

# Cell
def load_endpoints_df(endpoints_fp: str='data/endpoints.csv'):
    df_endpoints = pd.read_csv(endpoints_fp)

    date_idxs = (df_endpoints['Sample Data'].str.count('/')==2).replace(np.nan, False)
    time_idxs = df_endpoints['Sample Data'].str.contains(':').replace(np.nan, False)

    df_endpoints.loc[date_idxs & ~time_idxs, 'Sample Data'] = pd.to_datetime(df_endpoints.loc[date_idxs & ~time_idxs, 'Sample Data']).dt.strftime('%Y-%m-%d')
    df_endpoints.loc[date_idxs & time_idxs, 'Sample Data'] = pd.to_datetime(df_endpoints.loc[date_idxs & time_idxs, 'Sample Data']).dt.strftime('%Y-%m-%d %H:%M:%S')

    df_endpoints['Sample Data'] = df_endpoints['Sample Data'].fillna('')
    df_endpoints['Field Name'] = df_endpoints['Field Name'].str.replace(' ', '')

    return df_endpoints

# Cell
def get_endpoint_single_attr(df_endpoint, attribute='version'):
    attr_val = df_endpoint[attribute].unique()
    assert len(attr_val)==1, f'Expected only 1 {attribute}, instead found {len(attr_val)}'
    attr_val = attr_val[0]

    return attr_val

# Cell
def init_stream_dict(df_endpoint, endpoint_id):
    version = get_endpoint_single_attr(df_endpoint, 'version')
    name = get_endpoint_single_attr(df_endpoint, 'name')
    tags = get_endpoint_single_attr(df_endpoint, 'tags')

    stream = dict()

    stream['endpoint'] = f'/BMRS/{endpoint_id}/v{version}'
    stream['x-title'] = endpoint_id
    stream['description'] = name
    stream['parameters'] = list()

    if isinstance(tags, str):
        stream['tags'] = tags.split(', ')

    return stream

# Cell
def add_params_to_stream_dict(
    df_endpoint: pd.DataFrame,
    stream: dict,
    field_type_map: dict={
        'String': 'string',
        'Int': 'integer',
        'int': 'integer',
        'Integer': 'integer',
        'Date': 'string'
    }
):
    for _, (param_name, param_type, param_sample) in df_endpoint.query('direction=="request"')[['Field Name', 'Field Type', 'Sample Data']].iterrows():
        parameter = dict()

        parameter['name'] = param_name
        parameter['type'] = field_type_map[param_type]

        if param_type in ['Date']:
            parameter['format'] = 'date'

        if param_name == 'APIKey':
            parameter['format'] = 'password'

        if param_sample == 'csv/xml':
            parameter['examples'] = {f'{param_sub_sample}': {'value': param_sub_sample} for param_sub_sample in param_sample.split('/')}
        else:
            parameter['example'] = param_sample

        stream['parameters'] += [parameter]

    return stream

# Cell
def add_streams_to_spec(API_spec, df_endpoints):
    API_spec['streams'] = list()
    endpoint_ids = sorted(list(df_endpoints['id'].unique()))

    for endpoint_id in endpoint_ids:
        df_endpoint = df_endpoints.query(f'id==@endpoint_id')

        stream = init_stream_dict(df_endpoint, endpoint_id)
        stream = add_params_to_stream_dict(df_endpoint, stream)

        API_spec['streams'] += [stream]

    return API_spec

# Cell
def construct_spec(
    df_endpoints: pd.DataFrame,
    title: str='BMRS API',
    description: str='API for the Elexon Balancing Mechanism Reporting Service',
    root_url: str='https://api.bmreports.com'
):
    API_spec = init_spec()
    API_spec = add_streams_to_spec(API_spec, df_endpoints)

    return API_spec

# Cell
def save_spec(
    API_spec: dict,
    in_fp: str='../templates/open_api_spec.yaml',
    out_fp: str='../data/BMRS_API.yaml'
):
    rendered_schema = Template(open(in_fp).read()).render(API_spec=API_spec)

    with open(out_fp, 'w') as f:
        try:
            f.write(rendered_schema)
        except e as exc:
            raise exc

# Cell
def load_API_yaml(fp='../data/BMRS_API.yaml'):
    with open(fp, 'r') as stream:
        try:
            API_yaml = yaml.safe_load(stream)
        except yaml.YAMLError as exc:
            raise exc

    return API_yaml