import os, datetime, hashlib
from flask import jsonify
from bson.objectid import ObjectId
import jwt, bcrypt
from util import database

jwt_secret = os.environ.get('JWT_SECRET')

def get_user_context(request, token):
  if not token: return None
  try:
    id = jwt.decode(token, jwt_secret)['sub']
    if id:
      db = database.get_db()
      user = db.users.find_one({'_id': ObjectId(id), 'keys': token})
      if user: user['currentToken'] = token
      return user
  except Exception as e:
    return None

def generate_api_token(user_id):
  print(user_id)
  payload = {
    'iat': datetime.datetime.utcnow(),
    'sub': str(user_id)
  }
  return jwt.encode(payload, jwt_secret, algorithm='HS256').decode("utf-8")

def create(data):
  if not data:
    return jsonify({'success': False, 'message': 'Invalid request'}), 400
  email = data.get('email', '').lower().strip()
  password = data.get('password', '')
  db = database.get_db()
  existing = db.users.find_one({'email': email})
  if not email or not password:
     return jsonify({'success': False, 'message': 'Invalid request'}), 400
  if existing:
    return jsonify({'success': False, 'message': 'An account with that email address already exists'}), 400
  hashed_password = bcrypt.hashpw(hashlib.sha256(password.encode('utf-8')).hexdigest().encode('utf-8'), bcrypt.gensalt())
  user_id = ObjectId()
  token = generate_api_token(user_id)
  db.users.insert_one({'_id': user_id, 'email': email, 'password': hashed_password.decode('utf-8'), 'createdAt': datetime.datetime.utcnow(), 'keys': [token]})
  return token

def login(data):
  if not data:
    return jsonify({'success': False, 'message': 'Invalid request'}), 400
  email = data.get('email', '').lower().strip()
  password = data.get('password', '')
  if not email or not password:
     return jsonify({'success': False, 'message': 'Invalid request'}), 400
  db = database.get_db()
  existing = db.users.find_one({'email': email})
  print(existing)
  if not existing:
    return jsonify({'success': False, 'message': 'Email address or password incorrect'}), 400
 
  incoming_pw = hashlib.sha256(data['password'].encode('utf-8')).hexdigest() 
  if bcrypt.checkpw(incoming_pw.encode('utf-8'), existing['password'].encode('utf-8')):
    token = generate_api_token(existing['_id'])
    db.users.update_one({'_id': existing['_id']}, {'$addToSet': {'keys': token}})
    return token
  return jsonify({'success': False, 'message': 'Email address or password incorrect'}), 400

def logout(user):
  db = database.get_db()
  db.users.update_one({'_id': user['_id']}, {'$pull': {'keys': user['currentToken']}})
  return jsonify({'success': True}), 200

def logout_others(user):
  db = database.get_db()
  keys = filter(lambda k: k != user['currentToken'], user.get('keys', []))
  db.users.update_one({'_id': user['_id']}, {'$set': {'keys': list(keys)}})
  return jsonify({'success': True}), 200

def logout_all(user):
  db = database.get_db()
  db.users.update_one({'_id': user['_id']}, {'$set': {'keys': []}})
  return jsonify({'success': True}), 200
