import threading

from sqlalchemy import Column, String, UnicodeText, Boolean, Integer, distinct, func

from emilia.modules.helper_funcs.msg_types import Types
from emilia.modules.sql import BASE, SESSION


class CustomFilters(BASE):
	__tablename__ = "cust_filters"
	chat_id = Column(String(14), primary_key=True)
	keyword = Column(UnicodeText, primary_key=True, nullable=False)
	reply = Column(UnicodeText, nullable=False)
	is_sticker = Column(Boolean, nullable=False, default=False)
	is_document = Column(Boolean, nullable=False, default=False)
	is_image = Column(Boolean, nullable=False, default=False)
	is_audio = Column(Boolean, nullable=False, default=False)
	is_voice = Column(Boolean, nullable=False, default=False)
	is_video = Column(Boolean, nullable=False, default=False)

	has_buttons = Column(Boolean, nullable=False, default=False)
	# NOTE: Here for legacy purposes, to ensure older filters don't mess up.
	has_markdown = Column(Boolean, nullable=False, default=False)

	# NEW FILTER
	# alter table cust_filters add column reply_text text;
	# alter table cust_filters add column file_type integer default 1;
	# alter table cust_filters add column file_id text;
	reply_text = Column(UnicodeText)
	file_type = Column(Integer, nullable=False, default=1)
	file_id = Column(UnicodeText, default=None)

	def __init__(self, chat_id, keyword, reply, is_sticker=False, is_document=False, is_image=False, is_audio=False,
				 is_voice=False, is_video=False, has_buttons=False, reply_text=None, file_type=1, file_id=None):
		self.chat_id = str(chat_id)  # ensure string
		self.keyword = keyword
		self.reply = reply
		self.is_sticker = is_sticker
		self.is_document = is_document
		self.is_image = is_image
		self.is_audio = is_audio
		self.is_voice = is_voice
		self.is_video = is_video
		self.has_buttons = has_buttons
		self.has_markdown = True

		self.reply_text = reply_text
		self.file_type = file_type
		self.file_id = file_id

	def __repr__(self):
		return "<Permissions for %s>" % self.chat_id

	def __eq__(self, other):
		return bool(isinstance(other, CustomFilters)
					and self.chat_id == other.chat_id
					and self.keyword == other.keyword)


class NewCustomFilters(BASE):
	__tablename__ = "cust_filters_new"
	chat_id = Column(String(14), primary_key=True)
	keyword = Column(UnicodeText, primary_key=True, nullable=False)
	text = Column(UnicodeText)
	file_type = Column(Integer, nullable=False, default=1)
	file_id = Column(UnicodeText, default=None)

	def __init__(self, chat_id, keyword, text, file_type, file_id):
		self.chat_id = str(chat_id)  # ensure string
		self.keyword = keyword
		self.text = text
		self.file_type = file_type
		self.file_id = file_id

	def __repr__(self):
		return "<Filter for %s>" % self.chat_id

	def __eq__(self, other):
		return bool(isinstance(other, CustomFilters)
					and self.chat_id == other.chat_id
					and self.keyword == other.keyword)


class Buttons(BASE):
	__tablename__ = "cust_filter_urls"
	id = Column(Integer, primary_key=True, autoincrement=True)
	chat_id = Column(String(14), primary_key=True)
	keyword = Column(UnicodeText, primary_key=True)
	name = Column(UnicodeText, nullable=False)
	url = Column(UnicodeText, nullable=False)
	same_line = Column(Boolean, default=False)

	def __init__(self, chat_id, keyword, name, url, same_line=False):
		self.chat_id = str(chat_id)
		self.keyword = keyword
		self.name = name
		self.url = url
		self.same_line = same_line


CustomFilters.__table__.create(checkfirst=True)
Buttons.__table__.create(checkfirst=True)

CUST_FILT_LOCK = threading.RLock()
BUTTON_LOCK = threading.RLock()
CHAT_FILTERS = {}


def get_all_filters():
	try:
		return SESSION.query(CustomFilters).all()
	finally:
		SESSION.close()


def add_filter(chat_id, keyword, reply, is_sticker=False, is_document=False, is_image=False, is_audio=False,
			   is_voice=False, is_video=False, buttons=None):
	global CHAT_FILTERS

	if buttons is None:
		buttons = []

	with CUST_FILT_LOCK:
		prev = SESSION.query(CustomFilters).get((str(chat_id), keyword))
		if prev:
			with BUTTON_LOCK:
				prev_buttons = SESSION.query(Buttons).filter(Buttons.chat_id == str(chat_id),
															 Buttons.keyword == keyword).all()
				for btn in prev_buttons:
					SESSION.delete(btn)
			SESSION.delete(prev)

		filt = CustomFilters(str(chat_id), keyword, reply, is_sticker, is_document, is_image, is_audio, is_voice,
							 is_video, bool(buttons))

		if keyword not in CHAT_FILTERS.get(str(chat_id), []):
			CHAT_FILTERS[str(chat_id)] = sorted(CHAT_FILTERS.get(str(chat_id), []) + [keyword],
												key=lambda x: (-len(x), x))

		SESSION.add(filt)
		SESSION.commit()

	for b_name, url, same_line in buttons:
		add_note_button_to_db(chat_id, keyword, b_name, url, same_line)


def new_add_filter(chat_id, keyword, reply_text, file_type, file_id, buttons):
	global CHAT_FILTERS

	if buttons is None:
		buttons = []

	with CUST_FILT_LOCK:
		prev = SESSION.query(CustomFilters).get((str(chat_id), keyword))
		if prev:
			with BUTTON_LOCK:
				prev_buttons = SESSION.query(Buttons).filter(Buttons.chat_id == str(chat_id),
															 Buttons.keyword == keyword).all()
				for btn in prev_buttons:
					SESSION.delete(btn)
			SESSION.delete(prev)

		filt = CustomFilters(str(chat_id), keyword, reply="there is should be a new reply", is_sticker=False, is_document=False, is_image=False, is_audio=False, is_voice=False, is_video=False, has_buttons=bool(buttons), reply_text=reply_text, file_type=file_type.value, file_id=file_id)

		if keyword not in CHAT_FILTERS.get(str(chat_id), []):
			CHAT_FILTERS[str(chat_id)] = sorted(CHAT_FILTERS.get(str(chat_id), []) + [keyword],
												key=lambda x: (-len(x), x))

		SESSION.add(filt)
		SESSION.commit()

	for b_name, url, same_line in buttons:
		add_note_button_to_db(chat_id, keyword, b_name, url, same_line)


def remove_filter(chat_id, keyword):
	global CHAT_FILTERS
	with CUST_FILT_LOCK:
		filt = SESSION.query(CustomFilters).get((str(chat_id), keyword))
		if filt:
			if keyword in CHAT_FILTERS.get(str(chat_id), []):  # Sanity check
				CHAT_FILTERS.get(str(chat_id), []).remove(keyword)

			with BUTTON_LOCK:
				prev_buttons = SESSION.query(Buttons).filter(Buttons.chat_id == str(chat_id),
															 Buttons.keyword == keyword).all()
				for btn in prev_buttons:
					SESSION.delete(btn)

			SESSION.delete(filt)
			SESSION.commit()
			return True

		SESSION.close()
		return False


def get_chat_triggers(chat_id):
	return CHAT_FILTERS.get(str(chat_id), set())


def get_chat_filters(chat_id):
	try:
		return SESSION.query(CustomFilters).filter(CustomFilters.chat_id == str(chat_id)).order_by(
			func.length(CustomFilters.keyword).desc()).order_by(CustomFilters.keyword.asc()).all()
	finally:
		SESSION.close()


def get_filter(chat_id, keyword):
	try:
		return SESSION.query(CustomFilters).get((str(chat_id), keyword))
	finally:
		SESSION.close()


def add_note_button_to_db(chat_id, keyword, b_name, url, same_line):
	with BUTTON_LOCK:
		button = Buttons(chat_id, keyword, b_name, url, same_line)
		SESSION.add(button)
		SESSION.commit()


def get_buttons(chat_id, keyword):
	try:
		return SESSION.query(Buttons).filter(Buttons.chat_id == str(chat_id), Buttons.keyword == keyword).order_by(
			Buttons.id).all()
	finally:
		SESSION.close()


def num_filters():
	try:
		return SESSION.query(CustomFilters).count()
	finally:
		SESSION.close()


def num_chats():
	try:
		return SESSION.query(func.count(distinct(CustomFilters.chat_id))).scalar()
	finally:
		SESSION.close()


def __load_chat_filters():
	global CHAT_FILTERS
	try:
		chats = SESSION.query(CustomFilters.chat_id).distinct().all()
		for (chat_id,) in chats:  # remove tuple by ( ,)
			CHAT_FILTERS[chat_id] = []

		all_filters = SESSION.query(CustomFilters).all()
		for x in all_filters:
			CHAT_FILTERS[x.chat_id] += [x.keyword]

		CHAT_FILTERS = {x: sorted(set(y), key=lambda i: (-len(i), i)) for x, y in CHAT_FILTERS.items()}

	finally:
		SESSION.close()


# ONLY USE FOR MIGRATE OLD FILTERS TO NEW FILTERS
def __migrate_filters():
	try:
		all_filters = SESSION.query(CustomFilters).distinct().all()
		for x in all_filters:
			if x.is_document:
				file_type = Types.DOCUMENT
			elif x.is_image:
				file_type = Types.PHOTO
			elif x.is_video:
				file_type = Types.VIDEO
			elif x.is_sticker:
				file_type = Types.STICKER
			elif x.is_audio:
				file_type = Types.AUDIO
			elif x.is_voice:
				file_type = Types.VOICE
			else:
				file_type = Types.TEXT

			if str(x.chat_id) != "-1001385057026":
				continue

			print(str(x.chat_id), x.keyword, x.reply, file_type.value)
			if file_type == Types.TEXT:
				filt = CustomFilters(str(x.chat_id), x.keyword, x.reply, file_type.value, None)
			else:
				filt = CustomFilters(str(x.chat_id), x.keyword, None, file_type.value, x.reply)

			SESSION.add(filt)
			SESSION.commit()

	finally:
		SESSION.close()


def migrate_chat(old_chat_id, new_chat_id):
	with CUST_FILT_LOCK:
		chat_filters = SESSION.query(CustomFilters).filter(CustomFilters.chat_id == str(old_chat_id)).all()
		for filt in chat_filters:
			filt.chat_id = str(new_chat_id)
		SESSION.commit()
		CHAT_FILTERS[str(new_chat_id)] = CHAT_FILTERS[str(old_chat_id)]
		del CHAT_FILTERS[str(old_chat_id)]

		with BUTTON_LOCK:
			chat_buttons = SESSION.query(Buttons).filter(Buttons.chat_id == str(old_chat_id)).all()
			for btn in chat_buttons:
				btn.chat_id = str(new_chat_id)
			SESSION.commit()


__load_chat_filters()