from flask import Flask, request, jsonify, g, url_for, abort
from flask_sqlalchemy import SQLAlchemy
from flask_httpauth import HTTPBasicAuth
from pymongo import MongoClient
from flasgger import Swagger
from flask_cors import CORS
from flasgger.utils import swag_from
from passlib.apps import custom_app_context as pwd_context
from dateutil.parser import parse as parse_datetime
from scripts import *
from itsdangerous import (TimedJSONWebSignatureSerializer
                          as Serializer, BadSignature, SignatureExpired)

client = MongoClient('127.0.0.1', 27017)
db = client['cvedb']
vulnscan_collection = db['todos']

#db_mgmt.py
defaultvalue = {}
defaultvalue['cwe'] = "Unknown"

# initialization
app = Flask(__name__)
app.config['SECRET_KEY'] = 'the quick brown fox jumps over the lazy dog'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite'
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True

# extensions
dbAuth = SQLAlchemy(app)
auth = HTTPBasicAuth()

CORS(app)
Swagger(app)
nm = nmap.PortScanner()

class User(dbAuth.Model):
    __tablename__ = 'users'
    id = dbAuth.Column(dbAuth.Integer, primary_key=True)
    username = dbAuth.Column(dbAuth.String(32), index=True)
    password_hash = dbAuth.Column(dbAuth.String(64))

    def hash_password(self, password):
        self.password_hash = pwd_context.encrypt(password)

    def verify_password(self, password):
        return pwd_context.verify(password, self.password_hash)

    def generate_auth_token(self, expiration=600):
        s = Serializer(app.config['SECRET_KEY'], expires_in=expiration)
        return s.dumps({'id': self.id})

    @staticmethod
    def verify_auth_token(token):
        s = Serializer(app.config['SECRET_KEY'])
        try:
            data = s.loads(token)
        except SignatureExpired:
            return None    # valid token, but expired
        except BadSignature:
            return None    # invalid token
        user = User.query.get(data['id'])
        return user

@auth.verify_password
def verify_password(username_or_token, password):
    print('USERNAME: {0}\n PASWORD: {1}'.format(username_or_token, password))
    user = User.verify_auth_token(username_or_token)
    if not user:
        print('IS NOT USER')
        credentials = {'user': username_or_token, 'pass': password}
        auth_response = verify_ers_auth(credentials)
        print(auth_response)
        if 'role' in auth_response.keys():
            if auth_response['role'] == 'admin' or auth_response['role'] == 'script' and auth_response['verified']:
                    print('PASSWORD AND USERNAME IS CORRECT')
                    if User.query.filter_by(username=username_or_token).first() is not None:
                        user = User.query.filter_by(username=username_or_token).first()
                        print('EXCEPTION, USER EXISTS, GET FROM SQLITE: {}'.format(user))
                    else:
                        user = User(username=username_or_token)
                        dbAuth.session.add(user)
                        dbAuth.session.commit()
                    print('USER COMMITED AND ASSIGNED TO G.USER')
                    g.user = user
                    return True
        else:
            return False

    print('TOKEN NOW')
    g.user = user
    return True

@app.route('/alive')
def healthz():
    return 'I''m ok, thanks!'

@app.route('/token')
@auth.login_required
def get_auth_token():
    duration = 120
    token = g.user.generate_auth_token(duration)
    return jsonify({'token': token.decode('ascii'), 'duration': duration})

@app.route('/update_db', methods=['POST'])
@auth.login_required
@swag_from('api-docs/update_db.yml')
def update_db():
    """
    GET: Returns the current CVE version on the database
    """

    response = update_collections()
    return jsonify(response)

@app.route('/last_status', methods=['GET'])
@auth.login_required
# @swag_from('api-docs/last_scan.yml')
def last_status():
    """
    GET: Returns the scan ips status(Pending, Ready)
    """
    last_id = status_last_id()
    max_status = 1000
    last_id = last_id != None and last_id or 1
    arr = []
    if last_id == 1:
        arr = [last_id]
    elif last_id < max_status:
        arr = [x for x in range(1, last_id+1)]
    else:
        arr = [x for x in range(1, max_status+1)]

    cursor = db['status'].find({'id':{"$in":arr}}, sort=[("id", -1)])
    results = [item for item in cursor]
    print('FIND STATUS: {}'.format(results))
    return JSONEncoder().encode(results)
