import asyncio
import aiocron
from async_timeout import timeout

import yaml
from yaml.loader import SafeLoader

import discord
import discord.utils
from discord import option
from discord.ext import commands

import mysql.connector
from mysql.connector import Error

import time
from datetime import date, datetime, tzinfo

import os

import flask

from easy_pil import Canvas, Editor, Font, Text, font, load_image_async
from PIL import Image, ImageDraw, ImageFont, ImageOps
import pytz
import socket

zeit = datetime.now()

time_date = zeit.strftime("%Y/%m/%d")
time_year = zeit.strftime("%Y")
time_month = zeit.strftime("%m")
time_day = zeit.strftime("%d")

time_time = zeit.strftime("%H:%M:%S")
time_hour = zeit.strftime("%H")
time_minute = zeit.strftime("%M")
time_second = zeit.strftime("%S")

time_datetime = zeit.strftime("%Y/%m/%d" "%H:%M:%S")


class Database(commands.Cog):
    
    def __init__(self, bot):
        self.bot = bot
        global path
        path = bot.path

# Die Methode "connect_database" wird definiert, die eine Datenbankverbindung herstellt.
async def connect_database(servername):
    # Die Datei "database.yaml" wird geöffnet und die Daten werden geladen.
    with open(fr'{path}/Configs/{servername}/database.yaml', encoding='utf8') as f:
        data = yaml.load(f, Loader=SafeLoader)

    try:
        # Eine Verbindung zur Datenbank wird mit den Daten aus der Datei "database.yaml" hergestellt.
        mydb = mysql.connector.connect(
            host=data["Config.Database"]["host"],
            user=data["Config.Database"]["username"],
            password=data["Config.Database"]["password"],
            database=data["Config.Database"]["database"]
        )

        # Ein Cursor wird erstellt, um Datenbankabfragen auszuführen.
        cursor = mydb.cursor()

    # Wenn eine Ausnahme auftritt, wird "False" zurückgegeben.
    except Exception:
        return False

    # Ein "database"-Objekt wird erstellt und zurückgegeben.
    database = [mydb, cursor]
    return database

# Die Methode "disconnect_database" wird definiert, um eine Datenbankverbindung zu trennen.
async def disconnect_database(database):
    try:
        # Der Cursor und die Datenbankverbindung werden geschlossen.
        database[1].close()
        database[0].close()
    # Wenn eine Ausnahme auftritt, wird "False" zurückgegeben.
    except Exception:
        return False
    return True

# Die Methode "select_database" wird definiert, um Daten aus der Datenbank abzurufen.
async def select_database(servername, sql):
    # Eine Datenbankverbindung wird hergestellt.
    connect = await connect_database(servername)
    # Wenn keine Verbindung hergestellt werden konnte, wird "False" zurückgegeben.
    if connect == False:
        return False
    else:
        try:
            # Die SQL-Abfrage wird ausgeführt.
            result = connect[1].execute(sql)
        # Wenn eine Ausnahme auftritt, wird die Verbindung getrennt und "False" zurückgegeben.
        except Exception:
            await disconnect_database(connect)
            return False  
        # Wenn Daten vorhanden sind, wird die Verbindung getrennt und die Daten zurückgegeben.
        if result != None or result != []:
            await disconnect_database(connect)
            return result
        # Wenn keine Daten vorhanden sind, wird die Verbindung getrennt und "False" zurückgegeben.
        else:
            await disconnect_database(connect)
            return False

# Die Methode "insert_database" wird definiert, um Daten in die Datenbank zu Schreiben.
async def insert_database(servername, sql, val):
    # Eine Datenbankverbindung wird hergestellt.
    connect = await connect_database(servername)
    # Wenn keine Verbindung hergestellt werden konnte, wird "False" zurückgegeben.
    if connect == False:
        return False
    else:
        try:
            # Die SQL-Abfrage wird ausgeführt und die Daten werden der Datenbank hinzugefügt.
            connect[1].execute(sql, val)
            # Die Transaktion wird durchgeführt.
            connect[0].commit()
        except Exception:
            # Wenn eine Ausnahme auftritt, wird die Verbindung getrennt und "False" zurückgegeben.
            await disconnect_database(connect)
            return False
        # Die Verbindung wird getrennt und "True" zurückgegeben, um anzuzeigen, dass die Daten erfolgreich hinzugefügt wurden.
        await disconnect_database(connect)
        return True

#Die Methode "update_database" wird definiert, um Daten in der Datenbank zu aktualisieren.
async def update_database(servername, sql):
    # Eine Datenbankverbindung wird hergestellt.
    connect = await connect_database(servername)
    # Wenn keine Verbindung hergestellt werden konnte, wird "False" zurückgegeben.
    if connect == False:
        return False
    else:
        try:
            # Die SQL-Abfrage wird ausgeführt und die Daten werden in der Datenbank aktualisiert.
            connect[1].execute(sql)
        except Exception:
            # Wenn eine Ausnahme auftritt, wird die Verbindung getrennt und "False" zurückgegeben.
            await disconnect_database(connect)
            return False
        # Die Verbindung wird getrennt und "True" zurückgegeben, um anzuzeigen, dass die Daten erfolgreich aktualisiert wurden.
        await disconnect_database(connect)
        return True      
        

def setup(bot):
    bot.add_cog(Database(bot))