import vlc
from fastapi import FastAPI
import asyncio
import csv
import time
from fastapi.middleware.cors import CORSMiddleware

# Create a local dictionary of channels from the csv file.
channels_dict = {}
with open("all_channels.csv", "r") as file:
    reader = csv.reader(file)
    for eachLine in reader:
        if len(eachLine) == 0:
            continue
        ch_name = eachLine[0]
        ch_link = eachLine[1]
        channels_dict.update({ch_name: ch_link})


class AddChannel:
    channels_list = []

    def __init__(self, name):
        AddChannel.channels_list.append(self)
        self.name = name
        self.link = channels_dict.get(self.name)

        # Initialize for drop monitoring
        self.last_discontinuity = 0
        self.last_checked_time = time.time()

        print("New channel: {0}".format(self.name))

        # Create VLC player instance (no video/audio output)
        #vlc_instance = vlc.Instance("--no-video --no-audio --vout dummy")
        vlc_instance = vlc.Instance("--no-audio --vout dummy --quiet --ts-csa2-ck=0000000000000000 --ts-csa-ck=0000000000000001")
        self.player = vlc_instance.media_player_new()

        if self.link.startswith("http") or self.link.startswith("https"):
            self.player.set_mrl(self.link)
        elif self.link.startswith("udp://"):
            self.player.set_mrl(self.link, "udp://")

    def play(self):
        print("playerPlay")
        self.player.play()

    def get_stats(self):
        print("getStats")
        s = vlc.MediaStats()
        m = self.player.get_media()
        m.get_stats(s)

        current_time = time.time()
        elapsed = current_time - self.last_checked_time

        drops_now = s.demux_discontinuity
        drop_diff = drops_now - self.last_discontinuity

        # Update every 60 seconds
        if elapsed >= 60:
            self.last_checked_time = current_time
            self.last_discontinuity = drops_now

        # Determine stream status
        if drop_diff == 0:
            status = "Healthy"
        elif 1 <= drop_diff <= 10:
            status = "Moderate Drop"
        else:
            status = "Highly Dropped"

        data = {
            "demux_bitrate": int(s.demux_bitrate * 8000),
            "demux_corrupted": s.demux_corrupted,
            "demux_discontinuity": drops_now,
            "demux_read_bytes": s.demux_read_bytes,
            "input_bitrate": int(s.input_bitrate * 8000),
            "read_bytes": s.read_bytes,
            "time": int((self.player.get_time() / (1000 * 60)) % 60),
            "drop_diff_1min": drop_diff,
            "status": status,
        }
        return data


# FastAPI Setup
app = FastAPI()
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Initialize channels
for ch_name, ch_link in channels_dict.items():
    print(ch_name, ch_link)
    AddChannel(name=ch_name)

channels_list = AddChannel.channels_list

print("-------------All Channels--------------")
print(channels_list)
print("---------------------------------------")


# Play all channels on startup
@app.on_event("startup")
def play():
    for each_channel in channels_list:
        each_channel.play()


# If UDP streams exist, clear buffer periodically

@app.on_event("startup")
async def startup_event():
    contain_udp = False
    for each_channel in channels_list:
        if "udp://" in each_channel.name:
            contain_udp = True

    if contain_udp:
        asyncio.create_task(clear_buffer())

    asyncio.create_task(monitor_channels())  # new watchdog

# API: Get stats of all channels
@app.get("/stats")
def get_stats():
    return [[channel.name, channel.get_stats()] for channel in channels_list]


# API: Get stats of specific channel
@app.get("/stats/{channel_name}")
def get_specific_stats(channel_name: str):
    outputOBJ = None
    for channelOBJ in channels_list:
        if channelOBJ.name == channel_name:
            outputOBJ = channelOBJ

    if outputOBJ is None:
        return {
            "ERROR": f"The channel '{channel_name}' is not in the list. Please check your configuration."
        }

    return outputOBJ.name, outputOBJ.get_stats()


# Periodically clears VLC buffer to avoid memory bloat
async def clear_buffer():
    while True:
        print("_____Clearing the buffer______")
        for channelOBJ in channels_list:
            channel_stats = channelOBJ.get_stats()
            channel_buffer = channel_stats["read_bytes"]
            if channel_buffer > 100:
                channelOBJ.player.stop()
                channelOBJ.player.play()
                print("Buffer of {0} has been cleared".format(str(channelOBJ.name)))
        await asyncio.sleep(5)


async def monitor_channels():
    while True:
        for channelOBJ in channels_list:
            stats = channelOBJ.get_stats()
            demux_bitrate = stats["demux_bitrate"]

            # Check VLC state
            state = channelOBJ.player.get_state()

            # If VLC not in good state → restart
            if state not in (vlc.State.Playing, vlc.State.Buffering):
                print(f"[RESTART] {channelOBJ.name} bad state: {state}")
                channelOBJ.player.stop()
                await asyncio.sleep(1)
                channelOBJ.player.play()
                continue  # skip rest of checks this round

            # If demux_bitrate is 0 → stalled → restart
            if demux_bitrate == 0:
                print(f"[RESTART] {channelOBJ.name} stalled (demux_bitrate=0)")
                channelOBJ.player.stop()
                await asyncio.sleep(1)
                channelOBJ.player.play()

        await asyncio.sleep(30)  # check every 10s
