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

from cogs.encrypting import encode, decode, encrypt, decrypt
from cogs.database import select_database, insert_database, update_database

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

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

    @commands.slash_command(name="rules", description="Senden des Regelwerkes")
    async def rules(
        self, ctx: discord.ApplicationContext
        ):
        with open(fr'{path}/Configs/server.yaml', encoding='utf8') as f:
            data = yaml.load(f, Loader=SafeLoader)
            try:
                servername = next(item["name"] for item in data["Config.Server"] if str(ctx.guild.id) == str(item["guild"]))
                checkback = await check_send(servername)
            except StopIteration:
                await ctx.respond("Error in Syntax", ephemeral=True)
                return

            if checkback != None:
                backsend = await send_rules(ctx, servername, checkback, self.bot)
                await ctx.respond(backsend, ephemeral=True)


async def check_send(servername):
    with open(fr'{path}/Configs/{servername}/rules.yaml', encoding='utf8') as f:
        data = yaml.load(f, Loader=SafeLoader)

    if data["Config.Enabled"] == True:

        if data["Config.Request_Enabled"] == False:
            methode = "no_request"
            if data["Config.Base"] == "Button":
                interactobject = "Button"

            if data["Config.Base"] == "Emoji":
                interactobject = "Emoji"

        if data["Config.Request_Enabled"] == True and data["Config.Personality_Enabled"] == False:
            methode = "request"
            interactobject = "Button"

        if data["Config.Request_Enabled"] == True and data["Config.Personality_Enabled"] == True:
            methode = "request_and_personaltiy"
            interactobject = "Button"

        checkback = [methode, interactobject]
        return checkback

    else:
        return


async def send_rules(ctx, servername, base, bot):
    with open(fr'{path}/Configs/{servername}/rules.yaml', encoding='utf8') as f:
        data = yaml.load(f, Loader=SafeLoader)

    guild = bot.get_guild(int(ctx.guild.id))
    channel = guild.get_channel(int(data["Config.Channel"]))

    methode = base[0]
    interactobject = base[1]

    length = len(data["Config.Text"][methode]["fields"])

    Embed = discord.Embed(
        title=data["Config.Text"][methode]["header"]["title"],
        url=data["Config.Text"][methode]["header"]["url"],
        description=data["Config.Text"][methode]["header"]["description"],
        color=int(data["Config.Text"][methode]["header"]["color"], 16)
    )
    for i in range(0, length, 1):
        Embed.add_field(
            name=data["Config.Text"][methode]["fields"][i]["name"],
            value=data["Config.Text"][methode]["fields"][i]["value"],
            inline=data["Config.Text"][methode]["fields"][i]["inline"]
        )
    Embed.set_footer(text=data["Config.Text"][methode]["footer"]["text"])

    if interactobject == "Button":
        view = discord.ui.View(timeout=None)
        view.add_item(RegelwerkButton(servername))
        await channel.send(embed=Embed, view=view)

    if interactobject == "Emoji":
        await channel.send(embed=Embed)

    backsend = data["Config.Messages"]["message_send"]
    return backsend


async def check_deviation(interaction, servername):
    with open(fr'{path}/Configs/{servername}/rules.yaml', encoding='utf8') as f:
        data = yaml.load(f, Loader=SafeLoader)

    if data["Config.Request_Enabled"] == False:
        methode = "no_request"

    if data["Config.Request_Enabled"] == True and data["Config.Personality_Enabled"] == False:
        methode = "request"

    if data["Config.Request_Enabled"] == True and data["Config.Personality_Enabled"] == True:
        methode = "request_and_personaltiy"

    if interaction.message.embeds[0].fields[-2].value != data["Config.Text"][methode]["fields"][-2]["value"]:
        return True
    
    if interaction.message.embeds[0].fields[-2].value == data["Config.Text"][methode]["fields"][-2]["value"]:
        return False


async def edit_rules(interaction, servername):
    with open(fr'{path}/Configs/{servername}/rules.yaml', encoding='utf8') as f:
        data = yaml.load(f, Loader=SafeLoader)

    if data["Config.Request_Enabled"] == False:
        methode = "no_request"

    elif data["Config.Request_Enabled"] == True and data["Config.Personality_Enabled"] == False:
        methode = "request"

    elif data["Config.Request_Enabled"] == True and data["Config.Personality_Enabled"] == True:
        methode = "request_and_personaltiy"

    length = len(data["Config.Text"][methode]["fields"])

    Embed = discord.Embed(
        title=data["Config.Text"][methode]["header"]["title"],
        url=data["Config.Text"][methode]["header"]["url"],
        description=data["Config.Text"][methode]["header"]["description"],
        color=int(data["Config.Text"][methode]["header"]["color"], 16)
    )
    for i in range(0, length, 1):
        Embed.add_field(
            name=data["Config.Text"][methode]["fields"][i]["name"],
            value=data["Config.Text"][methode]["fields"][i]["value"],
            inline=data["Config.Text"][methode]["fields"][i]["inline"]
        )
    Embed.set_footer(text=data["Config.Text"][methode]["footer"]["text"])

    await interaction.message.edit(embed=Embed)


async def check_role(interaction, servername):
    with open(fr'{path}/Configs/{servername}/rules.yaml', encoding='utf8') as f:
        data = yaml.load(f, Loader=SafeLoader)

    checksum = 0

    print(data["Config.Whitelist_Seperate"])

    if data["Config.Whitelist_Seperate"] == True:
        try:
            role = interaction.guild.get_role(int(data["Config.Roles"]["veryfied"]["roleid"]))
        except Exception as e:
            backsend = data["Config.Messages"]["config_error_role"] + " ```\n" + e + "\n```"
            return backsend

        if role in interaction.user.roles:
            return True
        else:
            return False
        
    else:
        for role in data["Config.Roles"]:
            if role == "required":
                pass
            else:
                try:
                    role = interaction.guild.get_role(int(data["Config.Roles"][role]["roleid"]))
                except Exception as e:
                    backsend = data["Config.Messages"]["config_error_role"] + " ```\n" + e + "\n```"
                    return backsend 
                checksum += 1

        if checksum == len(data["Config.Roles"]) - 1:
            if role in interaction.user.roles:
                return True
            else:
                return False


async def set_roles(interaction, servername):
    with open(fr'{path}/Configs/{servername}/rules.yaml', encoding='utf8') as f:
        data = yaml.load(f, Loader=SafeLoader)

    checksum = 0

    if data["Config.Whitelist_Seperate"] == True:
        try:
            role = interaction.guild.get_role(int(data["Config.Roles"]["veryfied"]["roleid"]))
        except Exception as e:
            backsend = data["Config.Messages"]["config_error_role"] + " ```\n" + e + "\n```"
            return backsend
        await interaction.user.add_roles(role)

        backsend = data["Config.Messages"]["accept_granted"]
        return backsend
    
    else:
        for role in data["Config.Roles"]:
            if role == "required":
                pass
            else:
                try:
                    role = interaction.guild.get_role(int(data["Config.Roles"][role]["roleid"]))
                except Exception as e:
                    backsend = data["Config.Messages"]["config_error_role"] + " ```\n" + str(e) + "\n```"
                    return backsend
                await interaction.user.add_roles(role)
                checksum += 1

        if checksum == len(data["Config.Roles"]) - 1:
            backsend = data["Config.Messages"]["accept_granted"]
            return backsend


async def check_input(values, servername):
    with open(fr'{path}/Configs/{servername}/rules.yaml', encoding='utf8') as f:
        data = yaml.load(f, Loader=SafeLoader)

    for i in values:
        if i[0] == "captcher":
            check_captcher = await check_input_captcher(i[1], servername)
            if check_captcher == True:
                pass

            if check_captcher == False:
                backsend = data["Config.Messages"]["captcher_denied"]
                return backsend

        elif i[0] == "name":
            check_name = await check_input_name(i[1])
            if check_name == True:
                pass

            if check_name == False:
                backsend = data["Config.Messages"]["denied_badword"]
                return backsend

        elif i[0] == "date":
            check_date = await check_input_date(i[1], servername)
            if check_date == True:
                pass

            elif check_date == False:
                backsend = data["Config.Messages"]["denied_date"]
                return backsend
            
            elif check_date == data["Config.Messages"]["config_error_integer"]:
                return check_date

    return True


async def check_input_captcher(value, servername):
    with open(fr'{path}/Configs/{servername}/rules.yaml', encoding='utf8') as f:
        data = yaml.load(f, Loader=SafeLoader)
    acceptword = data["Config.Request_word"]

    if value.lower() == acceptword.lower():
        return True
    else:
        return False


async def check_input_name(value):
    with open(fr'{path}/Configs/warnings.yaml', encoding='utf8') as f:
        data = yaml.load(f, Loader=SafeLoader)

    for x in data["Config.Blacklist"]:
        length = len(data["Config.Blacklist"][x])
        for i in range(0, length, 1):
            if value == data["Config.Blacklist"][x][i]["word"]:
                return False
    return True


async def check_input_date(value, servername):
    with open(fr'{path}/Configs/{servername}/rules.yaml', encoding='utf8') as f:
        data = yaml.load(f, Loader=SafeLoader)

    if value.count('.') == 2 and len(value) == 10:
        born = value.split(".")
        today = date.today()
        year = int(born[2])
        month = int(born[1])
        day =  int(born[0])
        old = today.year - year - ((today.month, today.day) < (month, day))

        try:
            request_age = int(data["Config.Request_age"])
        except ValueError:
            return data["Config.Messages"]["config_error_integer"]

        if int(old) >= int(request_age):
            return True
        
        else:
            return False
        
    else:
        return False


class RegelwerkButton(discord.ui.Button):
    def __init__(self, servername):
        with open(fr'{path}/Configs/{servername}/rules.yaml', encoding='utf8') as f:
            data = yaml.load(f, Loader=SafeLoader)

        super().__init__(
            emoji=f'{data["Config.Button"]["emoji"]}',
            label=f'{data["Config.Button"]["label"]}', 
            style=int(data["Config.Button"]["style"]),
            disabled=data["Config.Button"]["disabled"],
            custom_id=f'interaction:{self.__class__.__name__}',
        )

    async def callback(self, interaction: discord.Interaction):
        user = interaction.user
        with open(fr'{path}/Configs/server.yaml', encoding='utf8') as f:
            data = yaml.load(f, Loader=SafeLoader)
            try:
                servername = next(item["name"] for item in data["Config.Server"] if str(interaction.guild.id) == str(item["guild"]))
            except StopIteration:
                return

        with open(fr'{path}/Configs/{servername}/rules.yaml', encoding='utf8') as f:
            data = yaml.load(f, Loader=SafeLoader)

        deviation = await check_deviation(interaction, servername)
        if deviation == True:
            await edit_rules(interaction, servername)
            if interaction.response.is_done():
                await interaction.followup.send(data["Config.Messages"]["message_changed"], ephemeral=True)
            else:
                await interaction.response.send_message(data["Config.Messages"]["message_changed"], ephemeral=True)

        else:
            if data["Config.Require_Database"] == False:
                checkback_database = True
            else:
                sql = f"SELECT * FROM user WHERE member_id = '{interaction.user.id}'"
                checkback_database = await select_database(servername, sql)

            checkback_role = await check_role(interaction, servername)

            if data["Config.Request_Enabled"] == False and data["Config.Personality_Enabled"] == False:

                if checkback_database == True and checkback_role == True:
                    backsend = data["Config.Messages"]["allready_accepted"]

                elif checkback_database == True and checkback_role == False:
                    backsend = await set_roles(interaction, servername)

                elif checkback_database == False and checkback_role == True:
                    sql = (f"INSERT INTO user (member_id, firstname, name, birthdate) VALUES (%s, %s, %s, %s)")
                    val = (interaction.user.id, "Not Set", "Not Set", "Not Set")
                    backsend = await insert_database(servername, sql, val)

                elif checkback_database == False and checkback_role == False:
                    backrole = await set_roles(interaction, servername)
                    sql = (f"INSERT INTO user (member_id, firstname, name, birthdate) VALUES (%s, %s, %s, %s)")
                    val = (interaction.user.id, "Not Set", "Not Set", "Not Set")
                    backdatabase = await insert_database(servername, sql, val)
                    backsend = backrole + "\n" + backdatabase

                else:
                    pass

                if interaction.response.is_done():
                    await interaction.followup.send(backsend, ephemeral=True)
                else:
                    await interaction.response.send_message(backsend, ephemeral=True)

            else:
                if data["Config.Request_Enabled"] == True and checkback_role == False:
                    await interaction.response.send_modal(RegelwerkModal(title=f'{data["Config.Modal"]["title"]}', servername = servername))
                    return

                if data["Config.Personality_Enabled"] == True and checkback_role == False:
                    if checkback_database == None:
                        await interaction.response.send_modal(RegelwerkModal(title=f'{data["Config.Modal"]["title"]}', servername = servername))
                        return
                    else:
                        for entry in checkback_database:
                            if "not set" in entry.lower():
                                await interaction.response.send_modal(RegelwerkModal(title=f'{data["Config.Modal"]["title"]}', servername = servername))
                                return
                        else:
                            backsend = data["Config.Messages"]["allready_accepted"]

                else:
                    backsend = data["Config.Messages"]["allready_accepted"]

                if interaction.response.is_done():
                    await interaction.followup.send(backsend, ephemeral=True)
                else:
                    await interaction.response.send_message(backsend, ephemeral=True)


class RegelwerkModal(discord.ui.Modal):
    def __init__(self, servername, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)

        with open(fr'{path}/Configs/{servername}/rules.yaml', encoding='utf8') as f:
            data = yaml.load(f, Loader=SafeLoader)
            if len(data["Config.Modal"]["captcher"]["content"]) + len(data["Config.Modal"]["personality"]["content"]) <= 5:
                length_captcher = len(data["Config.Modal"]["captcher"]["content"])
                length_personality = len(data["Config.Modal"]["personality"]["content"])
            else:
                print('You have an error in your config! Only except maximum of 5 Inputfield for "captcher" and "Personality"')

        if data["Config.Personality_Enabled"] == True:
            for i in range(0, length_personality, 1):
                if data["Config.Modal"]["personality"]["content"][i]["style"].lower() == "short":
                    self.add_item(discord.ui.InputText(label=data["Config.Modal"]["personality"]["content"][i]["label"], placeholder=data["Config.Modal"]["personality"]["content"][i]["placeholder"], style=discord.InputTextStyle.short))

                elif data["Config.Modal"]["personality"]["content"][i]["style"].lower() == "long":
                    self.add_item(discord.ui.InputText(label=data["Config.Modal"]["personality"]["content"][i]["label"], placeholder=data["Config.Modal"]["personality"]["content"][i]["placeholder"], style=discord.InputTextStyle.long))
                else:
                    print('You have an error in config! only except "short" or "long"')
                    return

        if data["Config.Request_Enabled"] == True:
            for i in range(0, length_captcher, 1):
                if data["Config.Modal"]["captcher"]["content"][i]["style"].lower() == "short":
                    self.add_item(discord.ui.InputText(label=data["Config.Modal"]["captcher"]["content"][i]["label"], placeholder=data["Config.Modal"]["captcher"]["content"][i]["placeholder"], style=discord.InputTextStyle.short))

                elif data["Config.Modal"]["captcher"]["content"][i]["style"].lower() == "long":
                    self.add_item(discord.ui.InputText(label=data["Config.Modal"]["captcher"]["content"][i]["label"], placeholder=data["Config.Modal"]["captcher"]["content"][i]["placeholder"], style=discord.InputTextStyle.long))
                else:
                    print('You have an error in config! only except "short" or "long"')
                    return

    async def callback(self, interaction: discord.Interaction):
        user = interaction.user
        with open(fr'{path}/Configs/server.yaml', encoding='utf8') as f:
            data = yaml.load(f, Loader=SafeLoader)
            try:
                servername = next(item["name"] for item in data["Config.Server"] if str(interaction.guild.id) == str(item["guild"]))
            except StopIteration:
                return

        with open(fr'{path}/Configs/{servername}/rules.yaml', encoding='utf8') as f:
            data = yaml.load(f, Loader=SafeLoader)
            if len(data["Config.Modal"]["captcher"]["content"]) + len(data["Config.Modal"]["personality"]["content"]) <= 5:
                length_captcher = len(data["Config.Modal"]["captcher"]["content"])
                length_personality = len(data["Config.Modal"]["personality"]["content"])
            else:
                print('You have an error in your config! Only except maximum of 5 Inputfield for "captcher" and "Personality"')

        values = []
        length = len(self.children)

        for i in range(0, length, 1):
            for x in range(0, length_captcher, 1):
                if self.children[i].label == data["Config.Modal"]["captcher"]["content"][x]["label"]:
                    values.append([data["Config.Modal"]["captcher"]["content"][x]["action"], self.children[i].value])

            for x in range(0, length_personality, 1):
                if self.children[i].label == data["Config.Modal"]["personality"]["content"][x]["label"]:
                    values.append([data["Config.Modal"]["personality"]["content"][x]["action"], self.children[i].value])

        backcheck = await check_input(values, servername)

        if backcheck == True:
            if data["Config.Require_Database"] == False:
                backsend_database = True
            else:
                entry_values = []

                for value in values:
                    cryptval = await encrypt(value[1])
                    entry_values.append(cryptval)

                sql = (f"INSERT INTO user (member_id, firstname, name, birthdate) VALUES (%s, %s, %s, %s)")
                val = (interaction.user.id, entry_values[1], entry_values[0], entry_values[2])
                backsend_database = await insert_database(servername, sql, val)

            if backsend_database == True:
                backsend_roles = await set_roles(interaction, servername)

                if backsend_roles == True:
                    backsend = data["Config.Messages"]["accept_granted"]
                else:
                    backsend = backsend_roles
            else:
                backsend = data["Config.Messages"]["accept_denied"]
        else:
            backsend = backcheck

        if interaction.response.is_done():
            await interaction.followup.send(backsend, ephemeral=True)
        else:
            await interaction.response.send_message(backsend, ephemeral=True)


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