# Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import numpy as np
import random
import threading
import time
import logging
import queue

LOGGER = logging.getLogger(__name__)

class NetworkMetricsEmulator(threading.Thread):
    """
    This collector class will generate the emulated metrics for PKT_IN, PKT_OUT, BYTES_IN, BYTES_OUT and PKT_DROP as a list.
    """
    def __init__(self, interval=1, duration=10, metric_queue=None, network_state="moderate"):
        LOGGER.info("Initiaitng Emulator")
        super().__init__()
        self.interval            = interval
        self.duration            = duration
        self.metric_queue        = metric_queue if metric_queue is not None else queue.Queue()
        self.network_state       = network_state
        self.running             = True
        self.set_inital_parameter_values()

    def set_inital_parameter_values(self):
        self.bytes_per_pkt       = random.uniform(65, 150)
        self.states              = ["good", "moderate", "poor"]
        self.state_probabilities = {
            "good"    : [0.8, 0.2, 0.0],
            "moderate": [0.2, 0.6, 0.2],
            "poor"    : [0.0, 0.4, 0.6]
        }
        if self.network_state   == "good":
            self.packet_in = random.uniform(700, 900)
        elif self.network_state == "moderate":
            self.packet_in = random.uniform(300, 700)
        else:
            self.packet_in = random.uniform(100, 300)

    def generate_synthetic_data_point(self):
        if self.network_state   == "good":
            packet_loss  = random.uniform(0.01, 0.1)  
            random_noise = random.uniform(1,10)
        elif self.network_state == "moderate":
            packet_loss  = random.uniform(0.1, 1)
            random_noise = random.uniform(10, 40)
        elif self.network_state == "poor":
            packet_loss  = random.uniform(1, 3)
            random_noise = random.uniform(40, 100)
        else:
            raise ValueError("Invalid network state. Must be 'good', 'moderate', or 'poor'.")
        # self.packet_in += random_noise

        period        = 60 * 60 * random.uniform(10, 100)
        amplitude     = random.uniform(50, 100) 
        sin_wave      = amplitude  * np.sin(2 * np.pi   * 100 / period) + self.packet_in
        packet_in     = sin_wave   + ((sin_wave/100)    * random_noise)
        packet_out    = packet_in  - ((packet_in / 100) * packet_loss)
        bytes_in      = packet_in  * self.bytes_per_pkt
        bytes_out     = packet_out * self.bytes_per_pkt

        state_prob = self.state_probabilities[self.network_state]
        self.network_state = random.choices(self.states, state_prob)[0]
        print (self.network_state)

        return [float(packet_in), float(packet_out), float(bytes_in), float(bytes_out), float(packet_loss)]
        # return packet_in

    def run(self):
        while self.running and (self.duration == -1 or self.duration > 0):
            packet_in = self.generate_synthetic_data_point()
            self.metric_queue.put(packet_in)
            time.sleep(self.interval)  
            if self.duration > 0:
                self.duration -= self.interval
                if self.duration == -1:
                    self.duration = 0
        LOGGER.debug("Emulator collector is stopped.")
        self.stop()

    def stop(self):
        self.running = False
        if not self.is_alive():
            print("Thread is terminated.")
