import ssl
import discord
from discord import app_commands
from discord.ext import commands
import os, sys
import aiohttp
from datetime import datetime
from discord.ext import tasks
from discord.app_commands.errors import *
from player import *
import traceback
from exceptions import *
import asyncio, sys, argparse
from aiohttp.client_exceptions import ClientConnectionError

#Скрыть сообщение если надо ephemeral=True
class DiscordClient(commands.Bot):
	main_server_id = 0
	ANY_INPUT = "ссылка на стим | имя игрока | стимид | ид бана через #"
	discord2steam_cache = {}
	backend_url = ""
	secret_key = ""
	stats = {}
	show_stats_prev = 0
	loaded_extensions = {}

	def __init__(self, backend_url, secret_key):
		self.backend_url = backend_url
		self.secret_key = secret_key
		self.StartUpPreloadStats()
		###################################################
		super().__init__(command_prefix="!", intents=discord.Intents.all())
		#self.tree = app_commands.CommandTree(self)
		self.load_extensions(['user_ext', 'admin_ext', 'other_ext'])
		###################################################
		self.setup_events()

	def load_extensions(self, extensions_path):
		if type(extensions_path) == str:
			extensions_path = [extensions_path]
		for path in extensions_path:
			print(f"Load extensions from: {path}")
			sys.path.insert(0, path)
			for extension in os.listdir(path):
				extension, ext = os.path.splitext(extension)
				if ext != ".py":
					continue
				print(f"Loading: {extension}")
				self.loaded_extensions[extension] = __import__(extension).Extension(self)
			sys.path.pop(0)

	async def setup_hook(self):
		await self.GetStats()
		print("sync tree")
		if os.getenv("MAIN_DISCORD_SERVER_ID",""):
			self.main_server_id = int(os.getenv("MAIN_DISCORD_SERVER_ID"))
			await self.tree.sync(guild=discord.Object(self.main_server_id))
		await self.tree.sync()

		self.loop.create_task(self.loaded_extensions["stats_loader"].task())
		self.loop.create_task(self.loaded_extensions["stats_presence"].task())
		self.loop.create_task(self.loaded_extensions["vip_roles"].task())
		self.loop.create_task(self.loaded_extensions["ban_roles"].task())
		self.loop.create_task(self.loaded_extensions["register"].task())

	def setup_events(self):
		@self.event
		async def on_ready():
			print(f'Logged in as {self.user} (ID: {self.user.id})')
			print("Active guilds:")
			for guild in self.guilds:
				print(guild)

		@self.tree.error
		async def on_app_command_error(interaction, error):
			#надо сюда ебануть ошибки дискорда на даунов что делают не то что надо
			if isinstance(error, MissingRole):
				return await interaction.followup.send("Эту команду можно выполнить только на сервере где есть проверка ролей доступа!", ephemeral=True)
			elif isinstance(error, CommandNotFound):
				return await interaction.followup.send("У меня нет такой команды, возможно и есть...", ephemeral=True)
			elif isinstance(error.original, CannotCastToSteamID):
				return await interaction.followup.send("Не возможно найти такой профиль, попробуй написать иные данные!", ephemeral=True)
			elif isinstance(error.original, discord.app_commands.errors.NoPrivateMessage):
				return await interaction.followup.send("Вызванная тобой команда не работает в личных сообщениях", ephemeral=False)
			elif isinstance(error.original, LowPermition):
				return await interaction.followup.send("Это не для тебя и не для таких как ты сделано...", ephemeral=True)
			elif isinstance(error.original, AdminLowPermition):
				return await interaction.followup.send("Нельзя сделать это действие, ибо ты крут, но не настолько чтоб это совершить", ephemeral=True)
			elif isinstance(error.original, NotFoundPlayerOnServer):
				return await interaction.followup.send("Игрок не найден на серверах", ephemeral=True)
			elif isinstance(error.original, UnknownBackendResponse):
				return await interaction.followup.send("Ошибка на стороне сервера в исполнении говнокода, стоит подождать или позвать помощь", ephemeral=False)
			elif isinstance(error.original, discord.errors.NotFound):
				return await interaction.followup.send("Слишком долгий ответ со стороны сервера, причины:\n1) Возможно бекенд сдох\n2)Cлишком долгий незапланированный ответ с сервера\n3)Стоит позвать помощь", ephemeral=True)
			elif isinstance(error.original, NeedDiscordAuthOfSteam):
				return await interaction.followup.send("У тебя не привязан профиль стима к дискорду, ничего подобного делать тебе нельзя", ephemeral=True)
			elif isinstance(error.original, ClientConnectionError):
				return await interaction.followup.send("Сервис фактов13 не дал ответ, вероятно он умер, поэтому стоит немного подождать и может что-то изменится", ephemeral=True)
			traceback.print_exc()
			return await interaction.followup.send("Возникла необратимая ошибка, хз что случилось. Попробуй еще раз!", ephemeral=True)

	async def GetSteam64OfDiscord(self, user, no_cache = False):
		if user.id in self.discord2steam_cache and not no_cache:
			return self.discord2steam_cache[user.id]
		
		async with aiohttp.ClientSession(cookies={"secretkey":self.secret_key}) as session:
			async with session.get(f"{self.backend_url}/api/discord?discord_id={user.id}", ssl=False) as response:
				try:
					steamid_response = await response.json()
				except:
					raise NeedDiscordAuthOfSteam

				if response.status == 200 and steamid_response != None:
					self.discord2steam_cache[user.id] = steamid_response["steam64"]
				else:
					raise NeedDiscordAuthOfSteam
		
		return self.discord2steam_cache[user.id]
		
	async def GetPlayer(self, profile, requester_steam64, load_profile = True):
		player = Player(profile, requester_steam64, self.stats)
		await player.GetSteamID()
		if load_profile:
			await player.LoadProfile()
		return player

	async def GetStats(self):
		async with aiohttp.ClientSession() as session:
			async with session.get(f"{os.getenv('BACKEND_URL')}/api/stats", ssl=False) as response:
				self.stats = await response.json()
		return self.stats

	def GetServersChoice(self):
		"""
		@app_commands.command()
        @app_commands.describe(fruits='fruits to choose from')
        @app_commands.choices(fruits=[
            Choice(name='apple', value=1),
            Choice(name='banana', value=2),
            Choice(name='cherry', value=3),
        ])s
        async def fruit(interaction: discord.Interaction, fruits: Choice[int]):
            await interaction.response.send_message(f'Your favourite fruit is {fruits.name}.')"""
		servers = []
		if self.stats.get("servers", {}):
			for server_name, server in self.stats["servers"].items():
				servers.append(app_commands.Choice(name = server["name"], value=server_name))
		else:
			print("backend stats not pre loaded, use standarts")
			for i in range(1,10):
				servers.append(app_commands.Choice(name = f"srv{i}", value=f"srv{i}"))
		return servers

	def StartUpPreloadStats(self):
		print("pre load backend stats")
		asyncio.get_event_loop().run_until_complete(self.GetStats())
		if not self.stats:
			print("backend not working down bot")
			sys.exit(1)
		else:
			print("backend is up, continue build app")

	def utime2human(self, utime):
		return datetime.fromtimestamp(utime).strftime('%H:%M:%S %d.%m.%Y')

if __name__ == "__main__":
	print(f"Build date: {os.getenv('BUILDDATE', 'not setted in env')}")
	parser = argparse.ArgumentParser()
	parser.add_argument("--import-test", action="store_true", default=None)
	args = parser.parse_args()
	if args.import_test:
		DiscordClient("","")
		sys.exit(0)

	DiscordClient(
		os.getenv("BACKEND_URL"),
		os.getenv("BACKEND_SECRETKEY")
	).run(os.getenv("DISCORD_TOKEN"))