#
#   Copyright © 2021,2022 IsardVDI S.L.
#   Copyright © 2022 Evilham <contact@evilham.com>
#
#   This file is part of DD
#
#   DD is free software: you can redistribute it and/or modify
#   it under the terms of the GNU Affero General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or (at your
#   option) any later version.
#
#   DD is distributed in the hope that it will be useful, but WITHOUT ANY
#   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
#   FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
#   details.
#
#   You should have received a copy of the GNU Affero General Public License
#   along with DD. If not, see <https://www.gnu.org/licenses/>.
#
# SPDX-License-Identifier: AGPL-3.0-or-later
import base64
import json
import logging as log
import os
import sys
import traceback
from time import sleep
from uuid import uuid4

from flask import Response, jsonify, redirect, request, url_for
from flask_socketio import (
    SocketIO,
    close_room,
    disconnect,
    emit,
    join_room,
    leave_room,
    rooms,
    send,
)

from typing import TYPE_CHECKING, Any, Dict
if TYPE_CHECKING:
    from admin.flaskapp import AdminFlaskApp


def sio_event_send(app : "AdminFlaskApp", event : str, data : Dict[str, Any]) -> None:
    app.socketio.emit(
        event,
        json.dumps(data),
        namespace="/sio/events",
        room="events",
    )
    # TODO: Why on earth do we find these all over the place?
    sleep(0.001)


class Events:
    app : "AdminFlaskApp"
    eid : str
    title : str
    text : str
    total : int
    table : str
    type : str
    def __init__(self, app : "AdminFlaskApp", title : str, text : str="", total : int=0, table : str="", type : str="info") -> None:
        self.app = app
        # notice, info, success, and error
        self.eid = str(base64.b64encode(os.urandom(32))[:8])
        self.title = title
        self.text = text
        self.total = total
        # TODO: this is probably replacing the .table method????
        self.table = table
        self.item = 0
        self.type = type
        self.create()

    def create(self) -> None:
        log.info("START " + self.eid + ": " + self.text)
        self.app.socketio.emit(
            "notify-create",
            json.dumps(
                {
                    "id": self.eid,
                    "title": self.title,
                    "text": self.text,
                    "type": self.type,
                }
            ),
            namespace="/sio",
            room="admin",
        )
        sleep(0.001)

    def __del__(self) -> None:
        log.info("END " + self.eid + ": " + self.text)
        self.app.socketio.emit(
            "notify-destroy",
            json.dumps({"id": self.eid}),
            namespace="/sio",
            room="admin",
        )
        sleep(0.001)

    def update_text(self, text : str) -> None:
        self.text = text
        self.app.socketio.emit(
            "notify-update",
            json.dumps(
                {
                    "id": self.eid,
                    "text": self.text,
                }
            ),
            namespace="/sio",
            room="admin",
        )
        sleep(0.001)

    def append_text(self, text : str) -> None:
        self.text = self.text + "<br>" + text
        self.app.socketio.emit(
            "notify-update",
            json.dumps(
                {
                    "id": self.eid,
                    "text": self.text,
                }
            ),
            namespace="/sio",
            room="admin",
        )
        sleep(0.001)

    def increment(self, data : Dict[str, Any]={"name": "", "data": []}) -> None:
        self.item += 1
        log.info("INCREMENT " + self.eid + ": " + self.text)
        self.app.socketio.emit(
            "notify-increment",
            json.dumps(
                {
                    "id": self.eid,
                    "title": self.title,
                    "text": "["
                    + str(self.item)
                    + "/"
                    + str(self.total)
                    + "] "
                    + self.text
                    + " "
                    + data["name"],
                    "item": self.item,
                    "total": self.total,
                    "table": self.table,
                    "type": self.type,
                    "data": data,
                }
            ),
            namespace="/sio",
            room="admin",
        )
        sleep(0.0001)

    def decrement(self, data : Dict[str, Any]={"name": "", "data": []}) -> None:
        self.item -= 1
        log.info("DECREMENT " + self.eid + ": " + self.text)
        self.app.socketio.emit(
            "notify-decrement",
            json.dumps(
                {
                    "id": self.eid,
                    "title": self.title,
                    "text": "["
                    + str(self.item)
                    + "/"
                    + str(self.total)
                    + "] "
                    + self.text
                    + " "
                    + data["name"],
                    "item": self.item,
                    "total": self.total,
                    "table": self.table,
                    "type": self.type,
                    "data": data,
                }
            ),
            namespace="/sio",
            room="admin",
        )
        sleep(0.001)

    def reload(self) -> None:
        self.app.socketio.emit("reload", json.dumps({}), namespace="/sio", room="admin")
        sleep(0.0001)

    def table(self, event : str, table : str, data : Dict[str, Any]={}) -> None:
        # refresh, add, delete, update
        self.app.socketio.emit(
            "table_" + event,
            json.dumps({"table": table, "data": data}),
            namespace="/sio",
            room="admin",
        )
        sleep(0.0001)
