import threading
from collections import deque
import numpy as np
import time
import copy
import queue
import cv2
import asyncio

class ChannelData:
    def __init__(self, str_url, int_type, bool_run, deque_length,icount_max):
        self.cap = None         #该通道视频采集对象
        self.work_th = None     #该通道工作线程句柄
        self.b_model = False      #是否有运行模型线程
        self.bool_run = bool_run  # 线程运行标识

        self.str_url = str_url  #视频源地址
        self.int_type = int_type  #视频源类型,0-usb,1-rtsp,2-hksdk
        self.icount_max = icount_max  # 帧序列号上限
        self.lock = threading.RLock()  # 用于保证线程安全

        self.deque_frame = deque(maxlen=deque_length)   #视频缓冲区用于保存录像
        self.last_frame = None  # 保存图片数据
        self.frame_queue = queue.Queue(maxsize=1)
        self.counter = 0  #帧序列号--保存报警录像使用

    #添加一帧图片
    def add_deque(self, value):
        self.deque_frame.append(value)  #deque 满了以后会把前面的数据移除

    #拷贝一份数据
    def copy_deque(self):
        return copy.deepcopy(self.deque_frame)

    #获取最后一帧图片
    def get_last_frame(self):
        if self.b_model:
            # with self.lock:
            #     frame = self.last_frame
            # return frame

            #if not self.frame_queue.empty():
            try:
                frame = self.frame_queue.get(timeout=0.3)  #web传输没有做帧率控制了,可以超时时间长一点
            except queue.Empty:
                print("channel--frame None")
                return None
            # else:
            #     return None
            return frame
        else:   #如果没有运行,直接从cap获取画面
            if self.cap:
                ret, frame = self.cap.read()  # 除了第一帧,其它应该都是有画面的
                if not ret:
                    print("channel--frame None")
                    return None
                ret, frame_bgr_webp = cv2.imencode('.jpg', frame)
                if not ret:
                    buffer_bgr_webp = None
                else:
                    buffer_bgr_webp = frame_bgr_webp.tobytes()
                return buffer_bgr_webp
            return None

    def update_last_frame(self,buffer):
        if buffer:
            # with self.lock:
            #     self.last_frame = None
            #     self.last_frame = buffer

            # if self.frame_queue.full():
            #     try:
            #         print("channel--丢帧")
            #         self.frame_queue.get(timeout=0.01)
            #     except queue.Empty: #为空不处理
            #         pass
            # self.frame_queue.put(buffer)

            try:
                self.frame_queue.put(buffer,timeout=0.05)
            except queue.Full:
                #print("channel--未插入")
                pass

    #帧序列号自增 一个线程中处理,不用加锁
    def increment_counter(self):
        self.counter += 1
        if self.counter > self.icount_max:
            self.counter = 0

    def get_counter(self):
        return self.counter

    #清空数据,停止工作线程(若有 ,并删除deque 和 last_frame)
    def clear(self):
        start_time = time.time()
        with self.lock:
            if self.b_model:    #b_model为true,说明开启了工作线程
                self.bool_run = False
                self.work_th.join()  #等待通道对应的子线程,停止工作。
                #time.sleep(1)
                self.deque_frame.clear()
                self.last_frame = None                      #二选一
                self.frame_queue = queue.Queue(maxsize=1)  #二选一
                self.counter = 0

        end_time = time.time()
        execution_time = end_time - start_time
        print(f"停止一个通道线程,花费了: {execution_time} seconds")

    def stop_run(self):
        self.bool_run = False


class ChannelManager:
    def __init__(self):
        self.channels = {}
        self.cm_lock = threading.RLock()  # 用于保证字典操作的线程安全

    #增加节点
    def add_channel(self, channel_id, str_url, int_type, bool_run, deque_length=10,icount_max=100000):
        with self.cm_lock:
            if channel_id in self.channels:     #若已经有数据,先删除后再增加
                self.channels[channel_id].clear()  # 手动清理资源
                del self.channels[channel_id]
            ch_data = ChannelData(str_url, int_type, bool_run, deque_length, icount_max)
            self.channels[channel_id] = ch_data
            return ch_data

    #删除节点
    def delete_channel(self, channel_id):   #需要验证资源的释放清空
        with self.cm_lock:
            if channel_id in self.channels:
                self.channels[channel_id].clear()  # 手动清理资源
                self.channels[channel_id].cap.release()
                del self.channels[channel_id]

    #获取节点
    def get_channel(self, channel_id):
        with self.cm_lock:
            return self.channels.get(channel_id)

    #停止工作线程---要把视频采集线程停止掉
    def stop_channel(self,channel_id):
        with self.cm_lock:
            if channel_id == 0:
                # for clannel_id,clannel_data in self.channels.items():
                #     clannel_data.clear()
                for clannel_data in self.channels:
                    clannel_data.clear()    #停止工作线程,并清空业务数据
                    clannel_data.cap.release()  #停止视频采集线程,并是否采集资源

                self.channels.clear()   #清空整个字典
            else:
                if channel_id in self.channels:
                    self.channels[channel_id].clear()  # 手动清理资源
                    self.channels[channel_id].cap.release()
                    del self.channels[channel_id]

if __name__ == "__main__":
    # 示例使用
    manager = ChannelManager()
    manager.add_channel('channel_1', 'test', 123, True, deque_length=5)

    # 更新和读取操作
    manager.update_channel_deque('channel_1', 'data1')
    manager.update_channel_buffer('channel_1', np.array([[1, 2], [3, 4]]))
    manager.increment_channel_counter('channel_1')

    channel_data = manager.get_channel_data('channel_1')
    print(channel_data)