#!/usr/bin/env python3

from flask import Flask, render_template_string, request, redirect, url_for, make_response
import mysql.connector
import sys
import re
import uuid

# Flask App
app = Flask(__name__)

# MySQL Konfiguration
DB_CONFIG = {
    'host': 'localhost',
    'database': 'chatwebsite',
    'unix_socket': '/var/run/mysqld/mysqld.sock',
    'ssl_disabled': True
}

connection = mysql.connector.connect(**DB_CONFIG)
connection.autocommit = True
cursor = connection.cursor(buffered=True)

# HTML Inhalt der statischen Website
HTML_CONTENT = """
<!DOCTYPE html>
<html lang="de">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Schlichte Website</title>
    <style>
        body {
            font-family: sans-serif;
            margin: 0;
        }

        main {
            padding: 1em;
        }
    </style>
</head>
<body>

<div style="background-color: #ddd">
    {% if user %}
        <form action="/logout" method="post" style="float: right">
            <fieldset>
                <legend>Login</legend>
                <em>Eingeloggt als:</em><br>
                {{ user }}<br>
                <input type="submit" value="Ausloggen">
            </fieldset>
        </form>
    {% else %}
        <form action="/login" method="post" style="float: right">
            <fieldset>
                <legend>Login</legend>

                <input type="text" name="name" placeholder="Benutzername">
                <br>
                <input type="text" name="pass" placeholder="Passwort">
                <br>
                <input type="submit" value="Einloggen">
            </fieldset>
        </form>
    {% endif %}

    <form action="/register" method="post">
        <fieldset>
            <legend>Account anlegen</legend>

            <input type="text" name="name" placeholder="Benutzername">
            <br>
            <input type="text" name="pass" placeholder="Passwort">
            <br>
            <input type="submit" value="Registrieren">
        </fieldset>
    </form>
</div>

{% if status %}
    <em style="display: block; background-color: #aaa; padding: 1em">{{ status }}</em>
{% endif %}

<main>
    <h1 style="clear: both">Willkommen auf der Chatwebseite</h1>

    <h2>Nachrichten</h2>

    {{ messages | safe }}

    <br>
    <br>
    <br>

    {% if user %}
        <form action="/post" method="post">
            <input type="text" name="text" placeholder="Eigene Nachricht">
            <input type="submit" value="Abschicken">
        </form>
    {% endif %}
</main>

</body>
</html>
"""

def executeMulti(q):
    pattern = re.compile(r'''((?:[^;"']|"[^"]*"|'[^']*')+)''')
    for stm in pattern.split(q)[1::2]:
        if not stm.isspace():
            print(stm, file=sys.stderr)
            cursor.execute(stm)

def init_db():
    executeMulti("""
        DROP TABLE IF EXISTS users;
        DROP TABLE IF EXISTS messages;
        DROP TABLE IF EXISTS sessions;
        CREATE TABLE messages (
            id     INT AUTO_INCREMENT PRIMARY KEY,
            author VARCHAR(255),
            text   VARCHAR(255)
        );
        CREATE TABLE users (
            name     VARCHAR(255) PRIMARY KEY,
            password VARCHAR(255)
        );
        CREATE TABLE sessions (
            id   INT AUTO_INCREMENT PRIMARY KEY,
            user VARCHAR(255)
        );
        INSERT INTO users (name, password) VALUES ("admin", "testtest");
        INSERT INTO messages (author, text) VALUES ("admin", "Hallo");
    """)

def get_current_user():
    session_id = request.cookies.get("session_id")

    if session_id is not None:
        executeMulti(f"SELECT user FROM sessions WHERE id = '%s'" % session_id)
        user = cursor.fetchone()
        if user is not None:
            return user[0]

    return None

@app.route('/')
def index():
    messages = ""

    executeMulti("SELECT * FROM messages")
    for record in cursor.fetchall():
        messages = messages + str(record[0]) + " " + str(record[1]) + ": " + str(record[2]) + "<br>"

    return render_template_string(HTML_CONTENT, messages=messages, user=get_current_user(), status=request.args.get("status"))

@app.route('/post', methods=["POST"])
def post():
    user = get_current_user()
    if user is not None:
        executeMulti("INSERT INTO messages (author, text) VALUES ('%s', '%s')" % (get_current_user(), request.form["text"]))
        connection.commit()
        return redirect(url_for("index"))
    else:
        return redirect(url_for("index", status="Du musst dich erst einloggen."))

@app.route('/login', methods=["POST"])
def login():
    executeMulti("SELECT password FROM users WHERE name = '" + request.form["name"] + "'")
    correctPassword = cursor.fetchone()

    if correctPassword is not None and correctPassword[0] == request.form["pass"]:
        #x = uuid.uuid4()
        executeMulti(f"INSERT INTO sessions (user) VALUES ('{request.form['name']}')")
        connection.commit()
        #sessionid = x
        sessionid = cursor.lastrowid

        response = make_response(redirect(url_for("index")))
        response.set_cookie("session_id", str(sessionid))
        return response
    else:
        return redirect(url_for("index", status="Falsches Passwort!"))

@app.route('/logout', methods=["POST"])
def logout():
    executeMulti(f"DELETE FROM sessions WHERE id = '%s'" % request.cookies.get("session_id"))
    return redirect(url_for("index", status="Erfolgreich abgemeldet."))

@app.route('/register', methods=["POST"])
def register():
    executeMulti("INSERT INTO users (name, password) VALUES ('%s', '%s')" % (request.form["name"], request.form["pass"]))

    return redirect(url_for("index", status="Anmeldung entgegen genommen."))

if __name__ == '__main__':
    init_db()
    app.run(host='0.0.0.0', port=80)
