from flask import jsonify, request
import json
import requests
from lxconsole import db
from lxconsole.models import Server
from flask_login import login_required
from lxconsole.api.access_controls import privilege_check

def get_client_crt():
  return 'certs/client.crt'

def get_client_key():
  return 'certs/client.key'

@login_required
def api_containers_endpoint(endpoint):

  if not privilege_check(endpoint, request.args.get('id')):
    return jsonify({'data': [], 'metadata':[], 'error': 'not authorized', 'error_code': 403})


  if endpoint == 'add_instance':
    id = request.args.get('id')
    project = request.args.get('project')
    server = Server.query.filter_by(id=id).first()
    location = request.form.get('location')
    if location == 'none':
      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers?project=' + project
    else:
      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers?target=' + location + '&project=' + project
    client_cert = get_client_crt()
    client_key = get_client_key()

    if request.form.get('json'):
      data = request.form.get('json')
      results = requests.post(url, verify=server.ssl_verify, cert=(client_cert, client_key), data=data)
      return jsonify(results.json())

    data = {}
    data.update({'name': request.form.get('name')})
    data.update({'description': request.form.get('description')})
    data.update({'location': request.form.get('location')})
    #data.update({'type': request.form.get('type')})
    data.update({'instance_type': request.form.get('instance_type')})
    profiles = []
    profiles.append(request.form.get('profiles'))
    data.update({'profiles': profiles})

    source = {}
    if request.form.get('image') == 'none':
      source.update({'type': request.form.get('image')})
      data.update({'source': source})
    else:
      source.update({'type': 'image'})
      source.update({'fingerprint': request.form.get('image')})
      data.update({'source': source})

    config = {}
    config.update({'boot.autostart': request.form.get('boot.autostart')}) if request.form.get('boot.autostart') else False
    config.update({'boot.autostart.delay': request.form.get('boot.autostart.delay')}) if request.form.get('boot.autostart.delay') else False
    config.update({'boot.autostart.priority': request.form.get('boot.autostart.priority')}) if request.form.get('boot.autostart.priority') else False
    config.update({'boot.host_shutdown_timeout': request.form.get('boot.host_shutdown_timeout')}) if request.form.get('boot.host_shutdown_timeout') else False
    config.update({'boot.stop.priority': request.form.get('boot.stop.priority')}) if request.form.get('boot.stop.priority') else False

    config.update({'cloud-init.network-config': request.form.get('cloud-init.network-config')}) if request.form.get('cloud-init.network-config') else False
    config.update({'cloud-init.user-data': request.form.get('cloud-init.user-data')}) if request.form.get('cloud-init.user-data') else False
    config.update({'cloud-init.vendor-data': request.form.get('cloud-init.vendor-data')}) if request.form.get('cloud-init.vendor-data') else False

    config.update({'limits.cpu': request.form.get('limits.cpu')}) if request.form.get('limits.cpu') else False
    config.update({'limits.cpu.allowance': request.form.get('limits.cpu.allowance')}) if request.form.get('limits.cpu.allowance') else False
    config.update({'limits.cpu.priority': request.form.get('limits.cpu.priority')}) if request.form.get('limits.cpu.priority') else False
    config.update({'limits.disk.priority': request.form.get('limits.disk.priority')}) if request.form.get('limits.disk.priority') else False
    config.update({'limits.hugepages.64KB': request.form.get('limits.hugepages.64KB')}) if request.form.get('limits.hugepages.64KB') else False
    config.update({'limits.hugepages.1MB': request.form.get('limits.hugepages.1MB')}) if request.form.get('limits.hugepages.1MB') else False
    config.update({'limits.hugepages.2MB': request.form.get('limits.hugepages.2MB')}) if request.form.get('limits.hugepages.2MB') else False
    config.update({'limits.hugepages.1GB': request.form.get('limits.hugepages.1GB')}) if request.form.get('limits.hugepages.1GB') else False
    config.update({'limits.memory': request.form.get('limits.memory')}) if request.form.get('limits.memory') else False
    config.update({'limits.memory.enforce': request.form.get('limits.memory.enforce')}) if request.form.get('limits.memory.enforce') else False
    config.update({'limits.memory.swap.priority': request.form.get('limits.memory.swap.priority')}) if request.form.get('limits.memory.swap.priority') else False
    config.update({'limits.memory.swap': request.form.get('limits.memory.swap')}) if request.form.get('limits.memory.swap') else False
    config.update({'limits.network.priority': request.form.get('limits.network.priority')}) if request.form.get('limits.network.priority') else False
    config.update({'limits.processes': request.form.get('limits.processes')}) if request.form.get('limits.processes') else False

    config.update({'migration.incremental.memory': request.form.get('migration.incremental.memory')}) if request.form.get('migration.incremental.memory') else False
    config.update({'migration.incremental.memory.goal': request.form.get('migration.incremental.memory.goal')}) if request.form.get('migration.incremental.memory.goal') else False
    config.update({'migration.incremental.memory.iterations': request.form.get('migration.incremental.memory.iterations')}) if request.form.get('migration.incremental.memory.iterations') else False

    config.update({'nvidia.driver.capabilities': request.form.get('nvidia.driver.capabilities')}) if request.form.get('nvidia.driver.capabilities') else False
    config.update({'nvidia.runtime': request.form.get('nvidia.runtime')}) if request.form.get('nvidia.runtime') else False
    config.update({'nvidia.require.cuda': request.form.get('nvidia.require.cuda')}) if request.form.get('nvidia.require.cuda') else False
    config.update({'nvidia.require.driver': request.form.get('nvidia.require.driver')}) if request.form.get('nvidia.require.driver') else False

    config.update({'cluster.evacuate': request.form.get('cluster.evacuate')}) if request.form.get('cluster.evacuate') else False
    config.update({'linux.kernel_modules': request.form.get('linux.kernel_modules')}) if request.form.get('linux.kernel_modules') else False
    
    config.update({'raw.apparmor': request.form.get('raw.apparmor')}) if request.form.get('raw.apparmor') else False
    config.update({'raw.idmap': request.form.get('raw.idmap')}) if request.form.get('raw.idmap') else False
    config.update({'raw.lxc': request.form.get('raw.lxc')}) if request.form.get('raw.lxc') else False
    config.update({'raw.seccomp': request.form.get('raw.seccomp')}) if request.form.get('raw.seccomp') else False

    config.update({'security.devlxd': request.form.get('security.devlxd')}) if request.form.get('security.devlxd') else False
    config.update({'security.devlxd.images': request.form.get('security.devlxd.images')}) if request.form.get('security.devlxd.images') else False
    config.update({'security.idmap.base': request.form.get('security.idmap.base')}) if request.form.get('security.idmap.base') else False
    config.update({'security.idmap.isolated': request.form.get('security.idmap.isolated')}) if request.form.get('security.idmap.isolated') else False
    config.update({'security.idmap.size': request.form.get('security.idmap.size')}) if request.form.get('security.idmap.size') else False
    config.update({'security.nesting': request.form.get('security.nesting')}) if request.form.get('security.nesting') else False
    config.update({'security.privileged': request.form.get('security.privileged')}) if request.form.get('security.privileged') else False
    config.update({'security.protection.delete': request.form.get('security.protection.delete')}) if request.form.get('security.protection.delete') else False
    config.update({'security.protection.shift': request.form.get('security.protection.shift')}) if request.form.get('security.protection.shift') else False

    config.update({'security.syscalls.allow': request.form.get('security.syscalls.allow')}) if request.form.get('security.syscalls.allow') else False
    config.update({'security.syscalls.deny': request.form.get('security.syscalls.deny')}) if request.form.get('security.syscalls.deny') else False
    config.update({'security.syscalls.deny_compat': request.form.get('security.syscalls.deny_compat')}) if request.form.get('security.syscalls.deny_compat') else False
    config.update({'security.syscalls.deny_default': request.form.get('security.syscalls.deny_default')}) if request.form.get('security.syscalls.deny_default') else False
    config.update({'security.syscalls.intercept.bpf': request.form.get('security.syscalls.intercept.bpf')}) if request.form.get('security.syscalls.intercept.bpf') else False
    config.update({'security.syscalls.intercept.bpf.devices': request.form.get('security.syscalls.intercept.bpf.devices')}) if request.form.get('security.syscalls.intercept.bpf.devices') else False
    config.update({'security.syscalls.intercept.mknod': request.form.get('security.syscalls.intercept.mknod')}) if request.form.get('security.syscalls.intercept.mknod') else False
    config.update({'security.syscalls.intercept.mount': request.form.get('security.syscalls.intercept.mount')}) if request.form.get('security.syscalls.intercept.mount') else False
    config.update({'security.syscalls.intercept.mount.allowed': request.form.get('security.syscalls.intercept.mount.allowed')}) if request.form.get('security.syscalls.intercept.mount.allowed') else False
    config.update({'security.syscalls.intercept.mount.fuse': request.form.get('security.syscalls.intercept.mount.fuse')}) if request.form.get('security.syscalls.intercept.mount.fuse') else False
    config.update({'security.syscalls.intercept.mount.shift': request.form.get('security.syscalls.intercept.mount.shift')}) if request.form.get('security.syscalls.intercept.mount.shift') else False
    config.update({'security.syscalls.intercept.setxattr': request.form.get('security.syscalls.intercept.setxattr')}) if request.form.get('security.syscalls.intercept.setxattr') else False

    config.update({'snapshots.schedule': request.form.get('snapshots.schedule')}) if request.form.get('snapshots.schedule') else False
    config.update({'snapshots.schedule.stopped': request.form.get('snapshots.schedule.stopped')}) if request.form.get('snapshots.schedule.stopped') else False
    config.update({'snapshots.pattern': request.form.get('snapshots.pattern')}) if request.form.get('snapshots.pattern') else False
    config.update({'snapshots.expiry': request.form.get('snapshots.expiry')}) if request.form.get('snapshots.expiry') else False
  
    data.update({'config': config})
    results = requests.post(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
    
    return jsonify(results.json())


  if endpoint == 'delete_instance':
    id = request.args.get('id')
    project = request.args.get('project')
    name = request.form.get('name')
    server = Server.query.filter_by(id=id).first()
    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '?project=' + project
    client_cert = get_client_crt()
    client_key = get_client_key()
    results = requests.delete(url, verify=server.ssl_verify, cert=(client_cert, client_key))
    return jsonify(results.json())


  if endpoint == 'list_instances':
    id = request.args.get('id')
    project = request.args.get('project')
    server = Server.query.filter_by(id=id).first()
    recursion = request.args.get('recursion')
    if recursion == '1':
      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers?recursion=1&project=' + project
    elif recursion == '2':
      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers?recursion=2&project=' + project
    else:
      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers?project=' + project
    client_cert = get_client_crt()
    client_key = get_client_key()
    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
    instances = json.dumps(results.json())
    instances = json.loads(instances)
    if recursion == '0' or recursion == '1':
      return jsonify(instances)
    i = 0
    for instance in instances['metadata']:
      instances['metadata'][i]['memory'] = ''
      instances['metadata'][i]['disk'] = ''
      instances['metadata'][i]['ipv4_addresses'] = []
      instances['metadata'][i]['ipv6_addresses'] = []

      if 'state' in instance.keys():

        # Set memory information if exists
        if 'memory' in instance['state'].keys():
          if 'usage' in instance['state']['memory'].keys():
            memory = instance['state']['memory']['usage']
            if memory:
              instances['metadata'][i]['memory'] = memory

        # Set disk information if exists
        if 'disk' in instance['state'].keys():
          if 'root' in instance['state']['disk'].keys():
            if 'usage' in instance['state']['disk']['root'].keys():
              disk = instance['state']['disk']['root']['usage']
              if disk:  
                instances['metadata'][i]['disk'] = disk

        # Set network information if exists
        if 'network' in instance['state'].keys():
          networks = instance['state']['network']
          if networks:
            instances['metadata'][i]['ipv4_addresses'] = []
            for network in networks.keys():
              addresses = networks[network]['addresses']
              for address in addresses:
                if address['family'] == 'inet' and address['scope'] == 'global':
                  instances['metadata'][i]['ipv4_addresses'] += [ address['address'] + ' (' + network + ')' ]
            instances['metadata'][i]['ipv6_addresses'] = []
            for network in networks.keys():
              addresses = networks[network]['addresses']
              for address in addresses:
                if address['family'] == 'inet6' and address['scope'] == 'global':
                  instances['metadata'][i]['ipv6_addresses'] += [ address['address'] + ' (' + network + ')' ]
      i += 1
    return jsonify(instances)
   

  if endpoint == 'load_instance':
    id = request.args.get('id')
    project = request.args.get('project')
    name = request.form.get('name')
    server = Server.query.filter_by(id=id).first()
    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '?project=' + project
    client_cert = get_client_crt()
    client_key = get_client_key()
    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
    return jsonify(results.json())


  if endpoint == 'change_instance_state':
    id = request.args.get('id')
    project = request.args.get('project')
    name = request.form.get('name')
    action = request.form.get('action')
    server = Server.query.filter_by(id=id).first()
    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '/state?project=' + project
    client_cert = get_client_crt()
    client_key = get_client_key()
    data = { 'action': action }
    results = requests.put(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
    return jsonify(results.json())


  if endpoint == 'update_instance':
    id = request.args.get('id')
    project = request.args.get('project')
    name = request.args.get('name')
    server = Server.query.filter_by(id=id).first()
    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '?project=' + project
    client_cert = get_client_crt()
    client_key = get_client_key()

    if request.form.get('json'):
      data = request.form.get('json')
      results = requests.put(url, verify=server.ssl_verify, cert=(client_cert, client_key), data=data)
      return jsonify(results.json())

    data = {}
    data.update({'name': request.form.get('name')})
    results = requests.post(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
    return jsonify(results.json())
