from urllib.parse import urljoin
import sys
import json

import wordpress_util
import fylr_lib_plugin_python3.util as fylr_util


def oauth1(_: dict, info_json: dict):
    api_callback_token = info_json.get('api_user_access_token', '')
    if not api_callback_token:
        raise Exception('callback token not set')

    request = info_json.get('request', {})
    response = wordpress_util.oauth1(
        query_params=request.get('query', {}),
        plugin_url=urljoin(
            info_json.get('external_url', ''),
            request.get('request', {}).get('Path', ''),
        ),
        api_callback_token=api_callback_token,
    )

    return response


def transport_wp(stdin_json: dict, info_json: dict):
    response = stdin_json.get('export', {})
    if response is None:
        wordpress_util.raise_error('export not set')

    # read api information
    api_callback = info_json.get('api_callback', {})
    api_callback_url = api_callback.get('url', '')
    if not api_callback_url:
        raise Exception('callback url not set')

    # read from export definition
    export_def = response.get('export', {})
    if not export_def:
        wordpress_util.raise_error('export definition not set')
    export_id = export_def.get('_id', 0)
    if not export_id:
        raise Exception('export: id not set')

    # read from transport definition
    transport_def = info_json.get('transport', {})
    if not transport_def:
        raise Exception('transport not set')

    transport_uuid = transport_def.get('uuid')
    if not transport_uuid:
        raise Exception('transport.uuid not set')

    transport_opts = transport_def.get('options', {})
    wp_inst_uuid = transport_opts.get('wp_inst_uuid', '')
    wp_conf = (
        info_json.get('info', {})
        .get('config', {})
        .get('plugin', {})
        .get('easydb-wordpress-plugin', {})
        .get('config', {})
        .get('wordpress', {})
    )
    if not wp_conf:
        wordpress_util.raise_error('wordpress config not found')

    wp_inst = {}
    auth = {}
    for _wp_inst in wp_conf.get('wp_instances', []):
        auth = json.loads(_wp_inst['auth'])
        if auth.get('uuid', '') == wp_inst_uuid:
            wp_inst = _wp_inst
            break

    if not wp_inst:
        wordpress_util.raise_error('wordpress instance not found')

    wp_inst_url = wp_inst.get('url', '')
    wp_api_url = wordpress_util.build_wp_api_url(wp_inst_url)
    if not wp_api_url:
        wordpress_util.raise_error('api discovery failed')

    wp_media_url = f'{wp_api_url}/media'

    _, protocol, _state = wordpress_util.transport_files(
        wp_media_url=wp_media_url,
        fpath='.',
        files=response.get('_files', []),
        auth=auth,
        user_generated_displayname=transport_opts.get('user_generated_displayname', ''),
        source_name='fylr',
        export_id=export_id,
        transport_uuid=transport_uuid,
        api_callback_url=api_callback_url,
    )
    protocol = [f'Transport files to Wordpress Server: {wp_inst_url}'] + protocol

    response['_state'] = _state
    response['_transport_log'] = protocol

    return {
        'headers': {
            'Content-Type': 'application/json',
        },
        'body': response,
    }


if __name__ == '__main__':
    _registered_callbacks = {
        'oauth1': oauth1,
        'transport_wp': transport_wp,
    }

    if len(sys.argv) < 3:
        raise Exception('expect 2 args: [callback name] [info.json]')

    # load info from parameters
    callback_name = sys.argv[1].strip()
    if not callback_name in _registered_callbacks:
        raise Exception(
            f'unknown callback name {callback_name}. expect one of [{", ".join(_registered_callbacks.keys())}]'
        )

    # read export data from stdin if necessary
    # if the plugin is called via an extension, there is no stdin
    if callback_name in ['transport_wp']:
        stdin_json = json.loads(sys.stdin.read())
        sys.stdin.close()
    else:
        stdin_json = {}

    try:
        info_json = json.loads(sys.argv[2])

        response = _registered_callbacks[callback_name](stdin_json, info_json)

        body = response.get('body', {})
        if not body:
            fylr_util.stdout(str(response))
            exit(0)

        content_type = response.get('headers', {}).get('Content-Type', '')
        if content_type == 'application/json':
            # body will be dumped as json
            fylr_util.return_response(body)
        else:
            # for text/html: return body as it is
            fylr_util.stdout(str(body))
            exit(0)

    except Exception as e:

        response = stdin_json
        response['_state'] = 'failed'
        if not '_transport_log' in response:
            response['_transport_log'] = []
        response['_transport_log'] += fylr_util.get_exception_traceback(e)

        fylr_util.return_response(response)
