import jwt as pyjwt
import datetime
import bcrypt
import psycopg2
import psycopg2.extras
from flask import Flask, request, jsonify
import os
from dotenv import load_dotenv

# Flask App erstellen
app = Flask(__name__)
app.config['SECRET_KEY'] = 'supergeheimeschluessel'

# .env-Datei laden
load_dotenv()

# Zugriff auf die Umgebungsvariablen
DB_HOST = os.getenv("DB_HOST")
DB_PORT = os.getenv("DB_PORT")
DB_NAME = os.getenv("DB_NAME")
DB_USER = os.getenv("DB_USER")
DB_PASSWORD = os.getenv("DB_PASSWORD")

# Verbindung zur PostgreSQL-Datenbank herstellen
def connect_db():
    return psycopg2.connect(
        dbname=DB_NAME,
        user=DB_USER,
        password=DB_PASSWORD,
        host=DB_HOST,
        port=DB_PORT
    )

def create_tables():
    conn = connect_db()
    cur = conn.cursor()
    cur.execute('''
        CREATE TABLE IF NOT EXISTS users (
            id SERIAL PRIMARY KEY,
            username TEXT UNIQUE NOT NULL,
            password TEXT NOT NULL,
            is_active BOOLEAN DEFAULT TRUE,
            email TEXT UNIQUE NOT NULL,
            reset_password_token TEXT,
            reset_password_expires TIMESTAMP
        );
    ''')
    conn.commit()
    cur.close()
    conn.close()

def generate_jwt(user_id):
    payload = {
        'user_id': user_id,
        'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=1)
    }
    return pyjwt.encode(payload, app.config['SECRET_KEY'], algorithm='HS256')

def verify_jwt(token):
    try:
        payload = pyjwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256'])
        return payload['user_id']
    except pyjwt.ExpiredSignatureError:
        return None
    except pyjwt.InvalidTokenError:
        return None

def hash_password(password):
    return bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')

def check_password(password, hashed):
    return bcrypt.checkpw(password.encode('utf-8'), hashed.encode('utf-8'))

@app.route('/register', methods=['POST'])
def register():
    data = request.json
    username = data.get('username')
    email = data.get('email')
    password = data.get('password')
    
    if not username or not email or not password:
        return jsonify({'error': 'Alle Felder erforderlich'}), 400
    
    hashed_password = hash_password(password)
    
    conn = connect_db()
    cur = conn.cursor()
    try:
        cur.execute("INSERT INTO users (username, email, password) VALUES (%s, %s, %s) RETURNING id", (username, email, hashed_password))
        user_id = cur.fetchone()[0]
        conn.commit()
    except psycopg2.IntegrityError:
        return jsonify({'error': 'Benutzername oder E-Mail bereits vergeben'}), 400
    finally:
        cur.close()
        conn.close()
    
    return jsonify({'message': 'Benutzer registriert', 'user_id': user_id})

@app.route('/login', methods=['POST'])
def login():
    data = request.json
    username = data.get('username')
    password = data.get('password')
    
    conn = connect_db()
    cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
    cur.execute("SELECT * FROM users WHERE username = %s", (username,))
    user = cur.fetchone()
    cur.close()
    conn.close()
    
    if not user or not check_password(password, user['password']):
        return jsonify({'error': 'Ungültige Anmeldeinformationen'}), 401
    
    token = generate_jwt(user['id'])
    return jsonify({'token': token})

@app.route('/kasse', methods=['GET'])
def get_kasse():
    token = request.headers.get('Authorization')
    if not token:
        return jsonify({'error': 'Kein Token vorhanden'}), 401
    
    user_id = verify_jwt(token.split()[1])
    if not user_id:
        return jsonify({'error': 'Ungültiges Token'}), 401
    
    conn = connect_db()
    cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
    cur.execute("SELECT * FROM kasse ORDER BY timestamp DESC")
    rows = cur.fetchall()
    cur.close()
    conn.close()
    
    return jsonify([dict(row) for row in rows])

@app.route('/new_entry', methods=['POST'])
def new_entry():
    token = request.headers.get('Authorization')
    if not token:
        return jsonify({'error': 'Kein Token vorhanden'}), 401
    
    user_id = verify_jwt(token.split()[1])
    if not user_id:
        return jsonify({'error': 'Ungültiges Token'}), 401
    
    data = request.json
    beschreibung = data.get('beschreibung')
    wert = data.get('wert')
    typ = data.get('typ')
    bar = data.get('bar')
    
    if not beschreibung or wert is None or not typ or bar is None:
        return jsonify({'error': 'Alle Felder erforderlich'}), 400
    
    conn = connect_db()
    cur = conn.cursor()
    cur.execute("INSERT INTO kasse (beschreibung, wert, typ, bar) VALUES (%s, %s, %s, %s) RETURNING id", 
                (beschreibung, wert, typ, bar))
    entry_id = cur.fetchone()[0]
    conn.commit()
    cur.close()
    conn.close()
    
    return jsonify({'message': 'Eintrag erstellt', 'entry_id': entry_id})

if __name__ == '__main__':
    create_tables()
    app.run(debug=True, port=5001)