import psycopg2
import psycopg2.extras
import datetime
import os
from dotenv import load_dotenv

# ANSI Escape Codes für Farben und Unterstreichung
RESET = "\033[0m"  # Zurücksetzen auf Standard

RED = "\033[31m"  # Rote Schrift
GREEN = "\033[32m"  # Grüne Schrift
BLUE = "\033[34m"  # Blaue Schrift

BOLD = "\033[1m"  # Fett
ITALIC = "\033[3m"  # Kursiv
UNDERLINE = "\033[4m"  # Unterstreichen


# .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_table():
    conn = connect_db()
    cur = conn.cursor()
    cur.execute('''
        CREATE TABLE IF NOT EXISTS kasse (
            id SERIAL PRIMARY KEY,
            beschreibung TEXT NOT NULL,
            wert NUMERIC(10,2) NOT NULL,
            typ TEXT CHECK (typ IN ('Einnahme', 'Ausgabe')) NOT NULL,
            bar BOOLEAN NOT NULL,
            timestamp TIMESTAMP NOT NULL DEFAULT NOW(),
            rechnungsnummer TEXT,
            kommentar TEXT,
            anlass TEXT
        );
    ''')
    conn.commit()
    cur.close()
    conn.close()

def initial_setup():
    conn = connect_db()
    cur = conn.cursor()
    cur.execute("SELECT COUNT(*) FROM kasse;")
    count = cur.fetchone()[0]
    
    if count == 0:
        start_konto = float(input("Startwert Konto: "))
        start_bar = float(input("Startwert Bar: "))
        cur.execute("INSERT INTO kasse (beschreibung, wert, typ, bar) VALUES (%s, %s, %s, %s)",
                    ('Startwert Konto', start_konto, 'Einnahme', False))
        cur.execute("INSERT INTO kasse (beschreibung, wert, typ, bar) VALUES (%s, %s, %s, %s)",
                    ('Startwert Bar', start_bar, 'Einnahme', True))
        conn.commit()
    cur.close()
    conn.close()

def parse_timestamp(date_str, time_str):
    if not date_str:
        date_str = datetime.datetime.now().strftime("%d.%m.%y")
    if not time_str:
        time_str = datetime.datetime.now().strftime("%H:%M")
    return datetime.datetime.strptime(f"{date_str} {time_str}", "%d.%m.%y %H:%M")

def erfassen(typ):
    beschreibung = input("Beschreibung: ")
    wert = float(input("Wert: "))
    bar = input("Bar? (1 = Ja, 0 = Nein): ") == '1'
    rechnungsnummer = input("Rechnungsnummer (optional): ") or None
    kommentar = input("Kommentar (optional): ") or None
    anlass = input("Anlass (optional): ") or None
    date_str = input("Datum (TT.MM.JJ, leer für heute): ")
    time_str = input("Uhrzeit (HH:MM, leer für jetzt): ")
    timestamp = parse_timestamp(date_str, time_str)
    
    conn = connect_db()
    cur = conn.cursor()
    cur.execute("INSERT INTO kasse (beschreibung, wert, typ, bar, timestamp, rechnungsnummer, kommentar, anlass) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)",
                (beschreibung, wert, typ, bar, timestamp, rechnungsnummer, kommentar, anlass))
    conn.commit()
    cur.close()
    conn.close()
    print("Buchung erfasst!")
    exit = input(f"\nEnter -> zurück zum Menü ")

def umbuchung():
    wert = float(input("Betrag der Umbuchung: "))
    richtung = input("Umbuchung Richtung? (1 = Bar -> Konto, 0 = Konto -> Bar): ") == '1'
    date_str = input("Datum (TT.MM.JJ, leer für heute): ")
    time_str = input("Uhrzeit (HH:MM, leer für jetzt): ")
    timestamp = parse_timestamp(date_str, time_str)
    
    conn = connect_db()
    cur = conn.cursor()
    if richtung:
        cur.execute("INSERT INTO kasse (beschreibung, wert, typ, bar, timestamp, anlass, gegenueber) VALUES (%s, %s, %s, %s, %s, %s, %s)",
                    ('Umbuchung nach Konto', wert, 'Ausgabe', True, timestamp, 'Orga', 'SJTKD'))
        cur.execute("INSERT INTO kasse (beschreibung, wert, typ, bar, timestamp, anlass, gegenueber) VALUES (%s, %s, %s, %s, %s, %s, %s)",
                    ('Umbuchung von Bar', wert, 'Einnahme', False, timestamp, 'Orga', 'SJTKD'))
    else:
        cur.execute("INSERT INTO kasse (beschreibung, wert, typ, bar, timestamp, anlass, gegenueber) VALUES (%s, %s, %s, %s, %s, %s, %s)",
                    ('Umbuchung nach Bar', wert, 'Ausgabe', False, timestamp, 'Orga', 'SJTKD'))
        cur.execute("INSERT INTO kasse (beschreibung, wert, typ, bar, timestamp, anlass, gegenueber) VALUES (%s, %s, %s, %s, %s, %s, %s)",
                    ('Umbuchung von Konto', wert, 'Einnahme', True, timestamp, 'Orga', 'SJTKD'))
    conn.commit()
    cur.close()
    conn.close()
    print("Umbuchung erfasst!")
    exit = input(f"\nEnter -> zurück zum Menü ")

def kassenbestand():
    conn = connect_db()
    cur = conn.cursor()
    cur.execute("SELECT SUM(wert) FROM kasse WHERE typ='Einnahme' AND bar=True")
    einnahmen_bar = cur.fetchone()[0] or 0
    cur.execute("SELECT SUM(wert) FROM kasse WHERE typ='Ausgabe' AND bar=True")
    ausgaben_bar = cur.fetchone()[0] or 0
    cur.execute("SELECT SUM(wert) FROM kasse WHERE typ='Einnahme' AND bar=False")
    einnahmen_konto = cur.fetchone()[0] or 0
    cur.execute("SELECT SUM(wert) FROM kasse WHERE typ='Ausgabe' AND bar=False")
    ausgaben_konto = cur.fetchone()[0] or 0
    
    barbestand = einnahmen_bar - ausgaben_bar
    kontostand = einnahmen_konto - ausgaben_konto
    summe = barbestand + kontostand
    print(UNDERLINE + "Kassenbestand:" + RESET)
    print(BOLD + "Bar:   " + RESET + f"{einnahmen_bar - ausgaben_bar:>10.2f} €")
    print(BOLD + "Konto: " + RESET + f"{einnahmen_konto - ausgaben_konto:>10.2f} €\n==============")
    print(BOLD + "Summe: " + RESET + f"{summe:>10.2f} €")
    
    cur.close()
    conn.close()
    exit = input(f"\nEnter -> zurück zum Menü ")

def anzeigen(filter_typ=None):
    conn = connect_db()
    cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
    if filter_typ:
        cur.execute("SELECT * FROM kasse WHERE typ = %s ORDER BY timestamp ASC", (filter_typ,))
    else:
        cur.execute("SELECT * FROM kasse ORDER BY timestamp ASC")
    rows = cur.fetchall()
    for row in rows:
        formatted_date = row['timestamp'].strftime("%d.%m.%y")
        print(f"{row['id']:<4} {row['beschreibung']:<35} | " + f"{GREEN if row['typ']=='Einnahme' else RED}" + f"{row['wert']:>7} € " + RESET +  f" | {'Bar' if row['bar'] else 'Konto':<6} | {formatted_date} | {row['rechnungsnummer'] or '':<15} | {row['kommentar'] or '':<10} | {row['anlass'] or '':<10}")
    cur.close()
    conn.close()
    exit = input(f"\nEnter -> zurück zum Menü ")

def anzeigen_anlass():
    filter_typ = input("Anlass: ")
    conn = connect_db()
    cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
    cur.execute("SELECT * FROM kasse WHERE anlass = %s ORDER BY timestamp ASC", (filter_typ,))
    rows = cur.fetchall()
    for row in rows:
        formatted_date = row['timestamp'].strftime("%d.%m.%y")
        print(f"{row['id']:<4} {row['beschreibung']:<35} | " + f"{GREEN if row['typ']=='Einnahme' else RED}" + f"{row['wert']:>7} € " + RESET +  f" | {'Bar' if row['bar'] else 'Konto':<6} | {formatted_date} | {row['rechnungsnummer'] or '':<10} | {row['kommentar'] or '':<10}")
    
    cur.execute("SELECT SUM(wert) FROM kasse WHERE typ = 'Einnahme' AND anlass = %s", (filter_typ,))
    einnahmen = cur.fetchone()[0] or 0
    
    cur.execute("SELECT SUM(wert) FROM kasse WHERE typ='Ausgabe' AND anlass = %s", (filter_typ,))
    ausgaben = cur.fetchone()[0] or 0
    
    print(UNDERLINE + "\nBilanz:" + RESET)
    text="Einnahmen:"
    print(BOLD + f"{text:<8}" + RESET + GREEN + f"{einnahmen:>10.2f} €" + RESET)
    text="Ausgaben: "
    print(BOLD + f"{text:<8}" + RESET + RED + f"{ausgaben:>10.2f} €" + RESET + f"\n===================")
    summe = einnahmen - ausgaben
    COLOR = GREEN
    if summe<0:
        COLOR = RED
    text="Summe:    "
    print(BOLD + f"{text:<8}" + RESET + COLOR + f"{summe:>10.2f} €" + RESET)
    
    cur.close()
    conn.close()
    exit = input(f"\nEnter -> zurück zum Menü ")

def menu():
    create_table()
    initial_setup()
    while True:
        print(UNDERLINE + "\nKassenbuch Menü:" + RESET)
        print(BOLD + "(1)" + RESET + " Ausgabe erfassen")
        print(BOLD + "(2)" + RESET + " Einnahme erfassen")
        print(BOLD + "(3)" + RESET + " Kassenbestand anzeigen")
        print(BOLD + "(4)" + RESET + " Umsätze anzeigen")
        print(BOLD + "(5)" + RESET + " Ausgaben anzeigen")
        print(BOLD + "(6)" + RESET + " Einnahmen anzeigen")
        print(BOLD + "(7)" + RESET + " Umbuchung durchführen")
        print(BOLD + "(8)" + RESET + " Bilanz Veranstaltung")
        print(BOLD + "(0)" + RESET + " Beenden")
        auswahl = input("Auswahl: ")
        print("\n")
        if auswahl == '1': erfassen('Ausgabe')
        elif auswahl == '2': erfassen('Einnahme')
        elif auswahl == '3': kassenbestand()
        elif auswahl == '4': anzeigen()
        elif auswahl == '5': anzeigen('Ausgabe')
        elif auswahl == '6': anzeigen('Einnahme')
        elif auswahl == '7': umbuchung()
        elif auswahl == '8': anzeigen_anlass()
        elif auswahl == '0': break

if __name__ == "__main__":
    menu()
