#!/usr/bin/python3
# -*- coding: utf-8 -*-
import logging
import asyncio
import sys
import json
import time
import weakref
import traceback
import textwrap

from .AsyncClient import AsyncClient

from .SourceModAPI import SourceModAPI
from .Subscribe import GameEvents, Forwards

from .Utils import Utils
from .Config import Config
from .CommandHandlermg import CommandHandlermg
from .AccessManager import AccessManager
from .PlayerManager import PlayerManager
from .AudioManager import AudioManager

class Torchlight():
	def __init__(self, master):
		self.Logger = logging.getLogger(__class__.__name__)
		self.Master = master
		self.Config = self.Master.Config
		self.WeakSelf = weakref.ref(self)

		self.API = SourceModAPI(self.WeakSelf)
		self.GameEvents = GameEvents(self.WeakSelf)
		self.Forwards = Forwards(self.WeakSelf)

		self.DisableVotes = set()
		self.Disabled = 0
		self.LastUrl = None

	def InitModules(self):
		self.Access = AccessManager()
		self.Access.Load()

		self.Players = PlayerManager(self.WeakSelf)

		self.AudioManager = AudioManager(self.WeakSelf)

		self.CommandHandler = CommandHandlermg(self.WeakSelf)
		self.CommandHandler.Setup()

		self.GameEvents.HookEx("server_spawn", self.Event_ServerSpawn)
		self.GameEvents.HookEx("player_say", self.Event_PlayerSay)

	def SayChat(self, message, player=None):
		message = "\x0700FFFA[Torchlight]: \x01{0}".format(message)
		if len(message) > 976:
			message = message[:973] + "..."
		lines = textwrap.wrap(message, 244, break_long_words = True)
		for line in lines:
			asyncio.ensure_future(self.API.PrintToChatAll(line))

		if player:
			Level = 0
			if player.Access:
				Level = player.Access["level"]

			if Level < self.Config["AntiSpam"]["ImmunityLevel"]:
				cooldown = len(lines) * self.Config["AntiSpam"]["ChatCooldown"]
				if player.ChatCooldown > self.Master.Loop.time():
					player.ChatCooldown += cooldown
				else:
					player.ChatCooldown = self.Master.Loop.time() + cooldown

	def SayPrivate(self, player, message):
		message = "\x0700FFFA[Torchlight]: \x01{0}".format(message)
		if len(message) > 976:
			message = message[:973] + "..."
		lines = textwrap.wrap(message, 244, break_long_words = True)
		for line in lines:
			asyncio.ensure_future(self.API.PrintToChat(player.Index, line))

	def Reload(self):
		self.Config.Load()
		self.CommandHandler.NeedsReload = True

	async def Send(self, data):
		return await self.Master.Send(data)

	def OnPublish(self, obj):
		if obj["module"] == "gameevents":
			self.GameEvents.OnPublish(obj)
		elif obj["module"] == "forwards":
			self.Forwards.OnPublish(obj)

	def Event_ServerSpawn(self, hostname, address, ip, port, game, mapname, maxplayers, os, dedicated, password):
		self.DisableVotes = set()
		self.Disabled = 0

	def Event_PlayerSay(self, userid, text):
		if userid == 0:
			return

		Player = self.Players.FindUserID(userid)
		asyncio.ensure_future(self.CommandHandler.HandleCommand(text, Player))

	def __del__(self):
		self.Logger.debug("~Torchlight()")


class TorchlightHandler():
	def __init__(self, loop):
		self.Logger = logging.getLogger(__class__.__name__)
		self.Loop = loop if loop else asyncio.get_event_loop()
		self._Client = None
		self.Torchlight = None
		self.Config = Config()

		asyncio.ensure_future(self._Connect(), loop = self.Loop)

	async def _Connect(self):
		# Connect to API
		self._Client = AsyncClient(self.Loop, self.Config["SMAPIServer"]["Host"], self.Config["SMAPIServer"]["Port"], self)
		await self._Client.Connect()

		self.Torchlight = Torchlight(self)

		# Pre Hook for late load
		await self.Torchlight.GameEvents._Register(["player_connect", "player_activate"])
		await self.Torchlight.Forwards._Register(["OnClientPostAdminCheck"])

		self.Torchlight.InitModules()

		# Late load
		await self.Torchlight.GameEvents.Replay(["player_connect", "player_activate"])
		await self.Torchlight.Forwards.Replay(["OnClientPostAdminCheck"])

	async def Send(self, data):
		return await self._Client.Send(data)

	def OnPublish(self, obj):
		self.Torchlight.OnPublish(obj)

	def OnDisconnect(self, exc):
		self.Logger.info("OnDisconnect({0})".format(exc))
		self.Torchlight = None

		asyncio.ensure_future(self._Connect(), loop = self.Loop)

	def __del__(self):
		self.Logger.debug("~TorchlightHandler()")

