from flask import Flask, request
from flask_restful import Resource, Api
import etcd3
import json
import logging
from functools import wraps

from ldaptest import is_valid_ldap_user

def authenticate(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        if not getattr(func, 'authenticated', True):
            return func(*args, **kwargs)

        # pass in username/password !
        acct = basic_authentication()  # custom account lookup function

        if acct:
            return func(*args, **kwargs)

        flask_restful.abort(401)
    return wrapper

def readable_errors(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except etcd3.exceptions.ConnectionFailedError as e:
            raise UncloudException('Cannot connect to etcd: is etcd running and reachable? {}'.format(e))
        except etcd3.exceptions.ConnectionTimeoutError as e:
            raise UncloudException('etcd connection timeout. {}'.format(e))

    return wrapper


class DB(object):
    def __init__(self, config, prefix="/"):
        self.config = config

        # Root for everything
        self.base_prefix= '/nicohack'

        # Can be set from outside
        self.prefix = prefix

        self.connect()

    @readable_errors
    def connect(self):
        self._db_clients = []
        for endpoint in self.config.etcd_hosts:
            client = etcd3.client(host=endpoint, **self.config.etcd_args)
            self._db_clients.append(client)

    def realkey(self, key):
        return "{}{}/{}".format(self.base_prefix,
                                self.prefix,
                                key)

    @readable_errors
    def get(self, key, as_json=False, **kwargs):
        value, _ = self._db_clients[0].get(self.realkey(key), **kwargs)

        if as_json:
            value = json.loads(value)

        return value


    @readable_errors
    def set(self, key, value, as_json=False, **kwargs):
        if as_json:
            value = json.dumps(value)

        # FIXME: iterate over clients in case of failure ?
        return self._db_clients[0].put(self.realkey(key), value, **kwargs)


class Membership(Resource):
    def __init__(self, config):
        self.config = config

    def get(self):
        data = request.get_json(silent=True) or {}
        print("{} {}".format(data, config))
        return {'message': 'Order successful' }, 200

    def post(self):
        data = request.get_json(silent=True) or {}
        print("{} {}".format(data, config))
        return {'message': 'Order 2x successful' }, 200


class Order(Resource):
    def __init__(self, config):
        self.config = config

    @staticmethod
    def post():
        data = request.get_json(silent=True) or {}
        print("{} {}".format(data, config))


class Product(Resource):
    def __init__(self, config):
        self.config = config

        self.products = []
        self.products.append(
            { "name": "membership-free",
              "description": """
This membership gives you access to the API and includes a VPN
with 1 IPv6 address.
See https://redmine.ungleich.ch/issues/7747?
""",
              "uuid": "a3883466-0012-4d01-80ff-cbf7469957af",
              "recurring": True,
              "recurring_time_frame": "per_year",
              "features": [
                  { "name": "membership",
                    "price_one_time": 0,
                    "price_recurring": 0
                  }
              ]
            }
        )
        self.products.append(
            { "name": "membership-standard",
              "description": """
This membership gives you access to the API and includes an IPv6-VPN with
one IPv6 address ("Road warrior")
See https://redmine.ungleich.ch/issues/7747?
""",
              "uuid": "1d85296b-0863-4dd6-a543-a6d5a4fbe4a6",
              "recurring": True,
              "recurring_time_frame": "per_month",
              "features": [
                  { "name": "membership",
                    "price_one_time": 0,
                    "price_recurring": 5
                  }

              ]
            }
        )
        self.products.append(
            { "name": "membership-premium",
              "description": """
This membership gives you access to the API and includes an
IPv6-VPN with a /48 IPv6 network.
See https://redmine.ungleich.ch/issues/7747?
""",
              "uuid": "bfd63fd2-d227-436f-a8b8-600de74dd6ce",
              "recurring": True,
              "recurring_time_frame": "per_month",
              "features": [
                  { "name": "membership",
                    "price_one_time": 0,
                    "price_recurring": 5
                  }

              ]
            }
        )
        self.products.append(
            { "name": "ipv6-vpn-with-/48",
              "description": """
An IPv6 VPN with a /48 network included.
""",
              "uuid": "fe5753f8-6fe1-4dc4-9b73-7b803de4c597",
              "recurring": True,
              "recurring_time_frame": "per_year",
              "features": [
                  { "name": "vpn",
                    "price_one_time": 0,
                    "price_recurring": 120
                  }
              ]
            }
        )


    @staticmethod
    def post():
        data = request.get_json(silent=True) or {}
        print("{} {}".format(data, config))

    def get(self):
        data = request.get_json(silent=True) or {}
        print("{} {}".format(data, config))

        return self.products





if __name__ == '__main__':
    app = Flask(__name__)

    config = {}

    config['etcd_url']="https://etcd1.ungleich.ch"
    config['ldap_url']="ldaps://ldap1.ungleich.ch"

    api = Api(app)
    api.add_resource(Order, '/orders', resource_class_args=( config, ))
    api.add_resource(Product, '/products', resource_class_args=( config, ))
    api.add_resource(Membership, '/membership',  resource_class_args=( config, ))

    app.run(host='::', port=5000, debug=True)