import hashlib
from datetime import datetime
import config
import logging
from core.JabberBot import JabberBot
from slixmpp.stanza import Message
from time import sleep
from core.lib import run_process
from classes.Ticket import Ticket
from typing import List
from concurrent.futures import ThreadPoolExecutor
from core.SystemdKiller import SystemdKiller
from core.requesters import TicketRequester
from config import KEYS

botname = "open_access_request_pending"
operating_status = 320

JID = botname + "@" + config.JSERVER
PORT = config.PORT
PASSWORD = hashlib.md5((botname + config.PASSWORD).encode('utf-8')).hexdigest()

bot = JabberBot(JID, PASSWORD)

listen_to = [
    "test@ej.sharix-app.org",
    "open_template_bot@ej.sharix-app.org"
]
""" Список jid, от которых можно получать сообщения этому боту """

proceed_to = [
    JID,
    "open_st_request_declined@ej.sharix-app.org",
    "open_service_request_forcemajeure@ej.sharix-app.org"
]
""" Список jid, кому бот может отправлять сообщения в результате обработки заявки """

ASSIGNET_TO_ATTEMPTS = 3
""" Количество пользователей, которым будет отправлено сообщение """
INTERVAL_ATTEMPTS = 3
""" Количество сообщений, которые будут отправлены пользователю """
# INTERVAL_TIME = 30 * 60  # 30 минут в секундах
INTERVAL_TIME = 5 # Для проверки
""" Интервал времени между попытками отправки сообщения """

TEMP_TICKETS: List[Ticket] = []
""" Список тикетов для добавления в очередь обработки """
ID_TICKETS_FOR_REMOVE: List[int] = []
""" Список id тикетов для удаления """

ticket_requester = TicketRequester(KEYS.OPEN_ACCESS_REQUEST_PENDING)

def message_handler(msg: Message):
    """Обработчик входящих сообщений"""

    if msg['type'] in ('chat', 'normal'):
        text = msg['body']  # текст сообщения боту
        sender = msg['from']  # отправитель сообщения

        sender_name = str(sender).split("/")[0]
        if sender_name in listen_to:
            if text is not None:
                logging.info(f"Сообщение получено")

                # match ACTION:
                #     case "add_ticket":
                #         match sender_name:
                #             case "open_*_request_*":
                #                 TEMP_TICKETS.append(ticket)
                #     case "remove_ticket":
                #         ID_TICKETS_FOR_REMOVE.append(id)


def start_handler():
    """Событие запуска обработчика."""

    logging.info(">>>>>  %s  |---| %s  <<<<<", JID, PASSWORD)

    tickets: List[Ticket] = ticket_requester.all({"status": 320})

    with ThreadPoolExecutor() as executor:
        killer = SystemdKiller()

        while not killer.exit_event.is_set():
            # Получение тикетов от других обработчиков
            tickets += TEMP_TICKETS
            TEMP_TICKETS.clear()

            # Фильтрация тикетов от лишних id
            tickets = [ticket for ticket in tickets if ticket.id not in ID_TICKETS_FOR_REMOVE]
            ID_TICKETS_FOR_REMOVE.clear()

            # Параллельная обработка всех тикетов
            processed = list(executor.map(run_process(interval_attempts_unlimited, processing), tickets))
            
            # Фильтрация тикетов
            tickets = [t for t in processed if t is not None]
            
            logging.debug('Кол-во тикетов:' + str(len(tickets)))
            logging.debug("Sleep")
            killer.exit_event.wait(timeout=INTERVAL_TIME)


# START CUSTOM FUNCTIONS

def interval_attempts_unlimited(ticket: Ticket) -> None:
    logging.debug(f"Лимит попыток обработки тикета {ticket.id} исчерпан")
    

    response = ticket_requester.patch(ticket, {"status": 359})
    
    # TODO: implement send ticket changed to next handler
    # bot.send_message(JID, f"Сообщение отправлено {JID}: {datetime.now()}")
    # bot message:
    # {
    #   "action": "add_ticket"
    #   "ticket_id":      0
    #   "ticket_list_id": 0
    # }


def processing(ticket: Ticket) -> None:
    logging.debug(f"Начало обработки тикета {ticket.id}. Лимит: {ticket.interval_attempts}")

    message = f"Тикет {ticket.id} ожидает решения"

    # send_notification_to_admins(ticket, message)
    # bot.send_message(ticket.assigned_to, message)

    logging.debug(f"Конец обработки тикета {ticket.id}")


def send_notification_to_admins(ticket: Ticket, admins: List[str], message: str) -> None:
    """Отправка уведомления администратору о новом тикете."""
    for admin in admins:
        bot.send_message(admin, message)
    logging.info(f"Уведомление отправлено администраторам: {ticket.id}")


def set_assigned_to(ticket: Ticket) -> Ticket:
    """Проверка, назначен ли тикет на пользователя"""
    if ticket.assigned_to is None:
        # TODO: add function how select user from db
        # ticket.assigned_to = "username"

        # assigned_to = ticket_requester.patch(ticket, {"assigned_to": "open_access_request_pending@ej.sharix-app.org"})
        # ticket.assigned_to = assigned_to
        None
    return ticket


# def get_token():
#     return jsreq.requestGetToken(botname, PASSWORD, config.API_URL + "/auth/token/login/")

# def set_tasklist(token):
#     global tasklist

#     tasklist = []
#     tasklist = jsreq.requestGetList(token, config.API_URL + "/tickets/api/tickets/?list_id=10")


# END CUSTOM FUNCTIONS


#  ---------------------------------------
#  ---------------------------------------
#  ---------------------------------------
#  ---------------------------------------
#  ---------------------------------------


# # обработчик входящих сообщений
# def message_handler(conn, mess):
#     text = mess.getBody()  # текст сообщения боту
#     user = mess.getFrom()  # отправитель сообщения

#     print(str(user).split("/")[0])
#     if (str(user).split("/")[0]) in listen_to:
#         print(text)
#         print(mess)

#         if text is not None:
#             orderObj = jsreq.jsonToOrderTicket(text)
#             print(orderObj)
#             tasklist.append(orderObj)
#             bot.bot_log(str(datetime.now()) + " Поступивший заказ успешно добавлен в очередь обработки\n")


# def open_access_request_pending_wait(period, localtask):
#     bot.bot_log(botname + " " + str(datetime.now()) + " " + "Заказ ожидает\n")
#     time.sleep(period)

#     # ВАЖНО! Надо скорее всего через API редактировать заказ, иначе возможна потеря данных
#     localtask.title = localtask.title + "1"

#     # обязательно данный обработчик должен заканчиваться передачей заказа куда-то на обработку дальше - обратно или другому, иначе оно потеряется
#     bot.proceed_status(proceed_to[1], localtask)
#     bot.bot_log(botname + " " + str(datetime.now()) + " " + "Заказ перенаправлен\n")


# def open_access_request_pending_process(localtask):
#     bot.bot_log(botname + " " + str(datetime.now()) + " " + "Заказ в обработчике\n")

#     push_notifications(localtask)
#     open_access_request_pending_wait(100, localtask)


# # Пока не уверен
# def push_notifications(localtask):
#     # Отправка уведомлений
#     # ...
#     return True


# def open_access_request_pending():
#     while (len(tasklist)):
#         localtask = tasklist.pop(0)
#         bot.bot_log(botname + " " + datetime.now().strftime('%Y-%m-%d') + " " + "Заказ в очереди на обработке\n")
#         print("EACH TASKLIST", tasklist)

#         if (localtask.status != operating_status):
#             bot.proceed_status(proceed_to[-1], localtask)
#             bot.bot_log(botname + " " + str(datetime.now()) + " " + "Заказ не по адресу, перенаправляем на форсмажор\n")
#             continue

#         # if (localtask.title!="10"):
#         #     t1=threading.Thread(target=open_service_request_booked_wait, args=(5,localtask))
#         #     t1.start()

#         # if (localtask.title=="101"):
#         #     t1=threading.Thread(target=open_service_request_booked_process, args=(10,localtask))
#         #     t1.start()

#         t1 = threading.Thread(target=open_access_request_pending_process, args=(localtask))
#         t1.start()

#         # если никакие обработчики не подошли - отправляем обратно в очередь
#         bot.proceed_status(proceed_to[0], localtask)
#         print("Заказ возвращен в очередь\n")
#         print(tasklist)


# # пустой список заказов