'''PantherX Device Identity Service'''

import logging
import platform
import sys

import pkg_resources

from flask import Flask, request, jsonify, make_response, g
from px_device_identity import Device, is_superuser_or_quit, DeviceProperties
from px_device_identity.errors import SigningError
from werkzeug.middleware.proxy_fix import ProxyFix
from waitress import serve

from .cli import get_cl_arguments
from .log import *

log = logging.getLogger(__name__)

opsys = platform.system()
version = pkg_resources.require("px-device-identity-service")[0].version

app = Flask(__name__)
app.wsgi_app = ProxyFix(app.wsgi_app)

@app.before_request
def before_request():
    g.key_dir = app.config['key_dir']
    g.config_dir = app.config['config_dir']
    g.debug = app.config['debug']

@app.after_request
def cors_headers(response):
    response.headers['Access-Control-Allow-Origin'] = '127.0.0.1'
    if request.method == 'OPTIONS':
        response.headers['Access-Control-Allow-Methods'] = response.headers.get('Allow', '127.0.0.1')
        response.headers['Access-Control-Allow-Headers'] = request.headers.get('Access-Control-Request-Headers', '127.0.0.1')
        response.headers['Access-Control-Max-Age'] = '86400'  # 24 hours
    return response

@app.route('/sign', methods=['POST', 'OPTIONS'])
def sign():
    if request.method == 'OPTIONS':
        return make_response('', 204)

    log.info("Received new signing request.")
    log.info(request.json)

    provided_device_id = request.json.get("deviceId", None)
    message = request.json.get("message", None)

    if provided_device_id is None:
        return make_response(jsonify(description='Could not find required deviceId.'), 400)

    if message is None:
        return make_response(jsonify(description='Could not find required message.'), 400)

    try:
        device = Device(
            key_dir=g.key_dir,
            config_dir=g.config_dir,
        )
        device_properties: 'DeviceProperties' = device.properties
        actual_device_id = device_properties.id

        log.debug(
            f"Determined current key ({device_properties.key_type}) security to be {device_properties.key_security}"
        )

        if actual_device_id and actual_device_id == provided_device_id:
            log.info(f"=> Start signing process for {actual_device_id}")
            try:
                signed = device.sign(message)
                if signed:
                    return make_response(jsonify(signature=str(signed)), 202)
                else:
                    return make_response(jsonify(error='Unable to sign authentication request.'), 503)
            except SigningError as err:
                log.error(err)
                return make_response(jsonify(title='Unable to sign authentication request.', message=err.message), 503)

        else:
            log.error(f"Device ID {actual_device_id} does not match with provided ID {provided_device_id}.")
            return make_response(jsonify(description='Device ID does not match with provided ID.'), 400)
    except:
        log.error(sys.exc_info()[0])
        return make_response(jsonify(description='Error occurred during the signing process.'), 404)

def main():
    '''Runs PantherX Device Identity Service'''
    log.info('------')
    log.info('Welcome to PantherX Device Identity Service')
    log.info(f"v{version}")
    log.info('------')

    is_superuser_or_quit()
    
    cl_arguments = get_cl_arguments()
    port = cl_arguments['port']
    host = cl_arguments['host']
    key_dir = cl_arguments['key_dir']
    config_dir = cl_arguments['config_dir']
    debug = cl_arguments['debug']
    
    app.config['key_dir'] = key_dir
    app.config['config_dir'] = config_dir
    app.config['debug'] = debug
    
    if debug:
        ch.setLevel(logging.DEBUG)

    serve(app, host=host, port=port)

if __name__ == '__main__':
    main()
