import json
import os
import asyncio
import websockets
from common.runtime import load_root_env
from typing import List
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, HTTPException

load_root_env(__file__)

threshold_to_alarm = int(os.getenv('threshold_to_alarm'))
time_to_jam = int(os.getenv('time_to_jam'))
time_to_fresh = int(os.getenv('time_to_fresh'))
lochost = os.getenv('lochost')
locport = int(os.getenv('locport'))
jamhost = os.getenv('jamhost')
jamport = os.getenv('jamport')


# TODO Добавить обработку кнопки и водопад.


class FreqConfig:
    """
    Конфиг частот, отображаемых на планшете.
    Атрибуты:
            freq_config: Словарь с частотами и преднастройкой (вкл/выкл).
    """
    def __init__(self):
        self.freq_config = {
            '433': False,
            '500': False,
            '700': True,
            '868': True,
            '915': True,
            '1200': True,
            '1500': False,
            '2400': True,
            '5200': True,
            '5800': True
        }

    def get(self):
        return self.freq_config

    def get_status(self, freq):
        """
        Проверка активности выбранной частоты.
        :param freq: Частота для проверки.
        :return: Вкл/выкл.
        """
        return self.freq_config[freq]

    def set_active(self, freq: str, status: bool):
        """
        Переключение частоты в состояние вкл/выкл.
        :param freq: Частота для отключения/включения.
        :param status: Положение, в которое переключается частота (True - вкл, False - выкл).
        :return: None.
        """
        self.freq_config[freq] = status


app = FastAPI()
websocket_connections: List[WebSocket] = []
jam_server_connect = None
alarm = False
freqconfig = FreqConfig()


def check_active_tablets() -> None:
    """
    Проверка активных соединений с каким-либо планшетом.
    """
    if not websocket_connections:
        raise HTTPException(status_code=400, detail="No active WebSocket connections = No tablets in sight.")


async def send_to_tablets(package) -> None:
    """
    Рассылка данных по планшетам.
    :param package: Собранный пакет данных для отправки.
    """

    global alarm

    if not websocket_connections:
        print('Нет подключенных планшетов/клиентов.')
    else:
        for websocket in websocket_connections:
            try:
                print('Пытаемся отправить данные клиенту ', websocket)
                await websocket.send_json(package)
                print(f'Пакет {package} успешно отправлен.')
            except Exception as e:
                print(f"Не смогли отправить данные клиенту по вебсокету: {e}")


async def check_alarm(amplitude: int):
    if amplitude > threshold_to_alarm:
        return await send_jam_server_alarm()
    else:
        return False


# async def freq_active(freq: str):
#     """
#     Запуск скрина с частотой после ее активации в частотном конфиге.
#     :param freq: Частота для запуска скрина.
#     """
#
#     # TODO добавить чек частоты в скринах, а то вдруг мы запускаем скрин, а он уже запущен.
#     print(f'АКТИВИРУЕМ ЧАСТОТУ {freq}')
#     command = f"screen -dmS {freq} sh -c \"export PYTHONPATH=/home/orangepi && bash -c \'python3 " \
#               f"/home/orangepi/DroneScanner/src/main_5800.py\' && exec bash\""
#     screen = subprocess.run(command, shell=True, capture_output=True, text=True)
#
#     # Проверяем результат выполнения
#     if screen.returncode == 0:
#         print("Команда успешно выполнена")
#     else:
#         print("Ошибка при выполнении команды")
#         print("STDERR:", screen.stderr)
#
#
# async def freq_deactive(freq: str):
#     """
#     Килл скрин с частотой после ее деактивации в частотном конфиге.
#     :param freq: Частота для скрин килл.
#     """
#
#     print(f'ОТКЛЮЧАЕМ ЧАСТОТУ {freq}')


@app.post('/send-waterfall/')
async def send_waterfall(data: dict) -> None:
    """
    Прием водопада и отсылка на планшеты, если необходимо.
    :param data: Водопад в виде пакета data = {...}
    """
    print('bubble tea!')


async def set_freq_config(data: dict):
    """
    Переключение состояний частот пришедших с одного планшета и рассылка этой информации на остальные.
    Запуск/отключение необходимых скринов.
    :param data: Словарь вида {частота: состояние}
    :return: None.
    """
    for freq, activ in data.items():
        freqconfig.set_active(freq, activ)
        print(f'Частота {freq} перешла в состояние {activ}: {freqconfig.get_status(freq)}')
        msg = {'type': 'freq_config',
               'data': {freq: activ}}
        await send_to_tablets(msg)
        # if activ:
        #     await freq_active(freq)
        #
        # else:
        #     await freq_deactive(freq)


@app.post("/process_data")
async def send_data(data: dict):
    """
    Прием данных со скриптов детекции в формате  data = {"freq": freq,
                                                        "amplitude": amplitude
                                                        }
    где freq - строка, amplitude - int, их обработка и рассылка по планшетам.
    :param data: Словарь.
    """

    global alarm
    global jam_server_connect
    # check_active_tablets()
    print('На сервер пришли данные: ', data)

    if alarm and jam_server_connect:
        print('Подавитель активен.')
        return {'message': 'Подавитель активен.'}
    elif alarm and jam_server_connect is None:
        alarm = False

    if not freqconfig.get_status(data['freq']):
        print('Частота выключена.')
        return {'message': 'Частота выключена.'}

    if await check_alarm(data['amplitude']):
        print('Затриггерились')

    msg = {'type': 'freq',
           'data': data
           }

    await send_to_tablets(msg)


@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket) -> None:
    """
    Прием данных (freq config) по вебсокету от клиента (планшетов) и их обработка.
    При подключении к серверу - отсылка на клиента текущее состояние частотного конфига.
    :param websocket:
    :return:
    """
    await websocket.accept()
    websocket_connections.append(websocket)
    msg = {'type': 'freq_config',
           'data': freqconfig.get()
           }
    await websocket.send_json(msg)
    try:
        while True:
            try:
                data_from_client = await websocket.receive_json()  # Ожидание получения данных от клиента
                if 'freq' in data_from_client:
                    data = data_from_client['freq']
                    print('Приняли с планшета: ', data)
                    await set_freq_config(data)
            except WebSocketDisconnect:
                print("Client disconnected")
                websocket_connections.remove(websocket)
                break
            except Exception as e:
                print(f"Error receiving data: {e}")
    except WebSocketDisconnect:
        websocket_connections.remove(websocket)
        # print(e)
        # print(f"Client disconnected: {e.code} - {e.reason}")


##################################################################################
# Подключение к серверу глушилок, как клиент по вебсокету и обработка информации.
##################################################################################
async def jammer_active():
    """
    Активируем подавитель.
    """

    global alarm
    print('АКТИВИРУЕМ ПОДАВИТЕЛЬ!!!!')
    alarm = True


async def jammer_deactive():
    """
    Отключаем подавитель.
    """

    global alarm
    print('ОТКЛЮАЕМ ПОДАВИТЕЛЬ!!!!')
    alarm = False


async def send_jam_server_alarm():
    """
    Отправить пакет с триггером на сервер подавителей.
    :return: True, если соединение с сервером активно и данные отправлены успешно. False - иначе.
    """

    global jam_server_connect
    msg = {'type': 'freq_alarm',
           'data': True}
    if jam_server_connect:
        await jam_server_connect.send(json.dumps(msg))
        return True
    else:
        return False


async def jam_server():
    """
    Подключиться к серверу подавителей по вебсокету как клиент. Получение и обработка пакетов - активация/деактивация
    подавителя.
    """
    uri = f'ws://{jamhost}:{jamport}/ws'
    global jam_server_connect
    while True:
        try:
            jam_server_connect = await websockets.connect(uri)
            while True:
                data_from_jam_server = await jam_server_connect.recv()
                data_from_jam_server = json.loads(data_from_jam_server)
                print('Принял с сервера глушилок: ', data_from_jam_server)
                if data_from_jam_server['type'] == 'run':
                    alarm_status = (data_from_jam_server['data'])['state']
                    print(alarm_status)
                    if alarm_status:
                        await jammer_active()
                    else:
                        await jammer_deactive()
        except Exception as e:
            jam_server_connect = None
            if alarm:
                await jammer_deactive()


@app.on_event("startup")
async def startup_event():
    """
    Запуск подключения к серверу подавления и получения от него сообщений.
    """

    asyncio.create_task(jam_server())


##################################################################################
# Запуск приложения.
##################################################################################
if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app, host=lochost, port=locport)
