from flask import Flask, render_template, request, jsonify, session
from flask_socketio import SocketIO, emit
from flask_cors import CORS
import requests
import uuid
import time
import os

app = Flask(__name__)

app.config["SECRET_KEY"] = "sdf5asdwer6df3asdf3565asdf"

socketio = SocketIO(cors_allowed_origins="*")
socketio.init_app(app)
CORS(app)

JANUS_URL = "https://bindaslive.com:8089/janus"
#JANUS_URL = "https://bindaslive.com/janus"
JANUS_API_SECRET = "your-secret-kedy"  # Use if authentication is required
roomId = 1234
sessions = {}
event = ""
myid = ""
mypvtid = ""
subscriber_mode = True
tracks = []
feedStreams = {}
sessions = {}
publishers = {}
ice_candidates = {}

@app.route('/')
def index():
    """Render the frontend."""
    return render_template('index.html')



def janus_event(end_point , data):
    headers = {"Content-Type": "application/json"}
    response = requests.post(f"{JANUS_URL}/{end_point}", json=data, headers=headers)
    return response.json()




# 1️⃣ **Create Janus Session**
@app.route('/create_session', methods=['POST'])
def create_session():
    data = {
        "janus": "create", 
        "transaction": str(uuid.uuid4())
        }

    session_data = janus_event("", data)
    session_id = session_data['data']['id']
    if session_id:
        sessions[session_id] = {}
    
    return jsonify(session_data)



# 2️⃣ **Attach VideoRoom Plugin**
@app.route('/attach_plugin', methods=['POST'])
def attach_plugin():
    session_id = request.json['session_id']
    data = {
        "janus": "attach", 
        "plugin": "janus.plugin.videoroom", 
        "transaction": str(uuid.uuid4())
        }
    response = janus_event(f'{session_id}', data)
    return jsonify(response)




# 3️⃣ **Join Video Room**
@app.route('/join_room', methods=['POST'])
def join_room():
    
    session_id = request.json['session_id']
    handle_id = request.json['handle_id']
    user_id = request.json['user_id']
    
    data = {
        "janus": "message",
        "body": {
            "request": "join",
            "ptype": "publisher",
            "room": roomId,
            "display": user_id
        },
        "transaction": str(uuid.uuid4())
    }

   
    response = janus_event(f"{session_id}/{handle_id}", data)
    
    if response["janus"] == "ack":
        # poll event after ack
        event_response = requests.get(f'{JANUS_URL}/{session_id}/events')
        print(event_response, 'event-join')
            
        return jsonify(event_response.json())
    
    return jsonify({"error": "Join room config error!!"})
    



# 4️⃣ **Publish Local Stream**
@app.route('/publish_stream', methods=['POST'])
def publish_stream():
    session_id = request.json['session_id']
    handle_id = request.json['handle_id']
    jsep = request.json['jsep']

    request_body = {
        "janus": "message",
        "body": {
            "request": "publish",
            "audio": True,
            "video": True
        },
        "jsep": jsep,
        "transaction": str(uuid.uuid4())
    }

    response = janus_event(f"{session_id}/{handle_id}", request_body)
    if response["janus"] == "ack":
        # poll event after ack
        event_response = requests.get(f'{JANUS_URL}/{session_id}/events')
        print(event_response, 'event-publish')
            
        return jsonify(event_response.json())
    
    return jsonify(response)
    



# 5️⃣ **Get Available Publishers**
@app.route('/get_publishers', methods=['POST'])
def get_publishers():
    
    session_id = request.json['session_id']
    handle_id = request.json['handle_id']
    
    data = {
            "janus": "message",
            "transaction": str(uuid.uuid4()),
            "body":{
                "request" : "listparticipants",
                "room": roomId    
            }
    }
    
    response = janus_event(f"{session_id}/{handle_id}", data)
    return jsonify(response)
    


# Check room exists or not

def room_exists(session_id, handle_id):
    data = {
        "janus": "message",
        "transaction": str(uuid.uuid4()),
        "body": {
            "request": "list",
            
        }
    }
    response = janus_event(f"{session_id}/{handle_id}", data)
    # Poll for a valid response
    events_response = requests.get(f"{JANUS_URL}/{session_id}/events").json()
    # Extract rooms list
    rooms = events_response.get("plugindata", {}).get("data", {}).get("list", [])
    # Check if the room exists
    return any(room["room"] == roomId for room in rooms)
    




# 6️⃣ **Subscribe to a Publisher**
@app.route('/subscribe', methods=['POST'])
def subscribe():
    
    session_id = request.json['session_id']
    feed_id = request.json['feed_id']
    
    # Step 1: Create a new handle for subscription
    
    data = {
        "janus": "attach", 
        "plugin": "janus.plugin.videoroom", 
        "transaction": str(uuid.uuid4())
        }
    
    handle_response = janus_event(f'{session_id}', data)
    
    if handle_response.get("janus") != "success":
        return jsonify({"error": "Failed to create subscriber handle"}), 500
    
    
    subscriber_handle_id = handle_response["data"]["id"]
   
    
    # Step 2: Fetch events to ensure the publisher is available
    for _ in range(5):  # Retry fetching events 5 times
        time.sleep(1)  # Wait before fetching events
        event_response = requests.get(f'{JANUS_URL}/{session_id}/events').json()
        print(event_response, 'Events response before subscribing')

        # Extract list of active publishers
        publishers = [event["id"] for event in event_response.get("plugindata", {}).get("data", {}).get("publishers", [])]

        if feed_id in publishers:
            break  # Feed ID found, proceed with subscription
        
        
        
        
        
        
        
    
    # Step 2: Join the room as a subscriber
  
    request_body = {
        "janus": "message",
        "body": {
            "request": "join",
            "ptype": "subscriber",
            "room": roomId,
            "feed": feed_id
        },
        "transaction": str(uuid.uuid4())
    }
    
    
    response = janus_event(f"{session_id}/{subscriber_handle_id}", request_body)
    print(response, 'subscribe-response')
    time.sleep(1)
    event_response = requests.get(f'{JANUS_URL}/{session_id}/events')
    print(event_response.json(), 'subscribe-event-response')
    return jsonify({
        "handle_id": subscriber_handle_id,  # Return new subscriber handle
        "event_response": event_response.json()
    })






# Store ICE candidates per feed
@app.route('/send_ice_candidate', methods=['POST'])
def send_ice_candidate():
    data = request.json
    feed_id = data['feed_id']
    candidate = data['candidate']
    
    session_id = request.json['session_id']
    # handle_id = request.json['handle_id']
    
    payload = {
        "janus": "trickle",
        "transaction": str(uuid.uuid4()),
        "candidate": candidate
    }

    # Send the ICE candidate to Janus
    response = janus_event(f"{session_id}/{feed_id}", payload)
    print( response , 'send_ice_candidate')
    
    event_response = requests.get(f'{JANUS_URL}/{session_id}/events')
    print( event_response.json(), 'event-ice-candidate')
    
    # if feed_id not in ice_candidates:
    #     ice_candidates[feed_id] = []
    
    # ice_candidates[feed_id].append(candidate)

    return jsonify(event_response.json())



# Retrieve ICE candidates
@app.route('/get_ice_candidates', methods=['POST'])
def get_ice_candidates():
    data = request.json
    
    session_id = data.get('session_id')
    handle_id = data.get('handle_id')
    
    if not session_id or not handle_id:
        return jsonify({"error": "Missing session_id or handle_id"}), 400

    data = {
        "janus": "message",
        "transaction": str(uuid.uuid4()),
        "body": {
            "request": "trickle",
            "candidate": "completed"
        }
    }

    response = janus_event(f"{session_id}/{handle_id}", data)
     # Fetch events from Janus for this session
    #event_response = requests.get(f'{JANUS_URL}/{session_id}/events').json()

    print(response, 'receive ice candidate')
    return jsonify({"candidates": response})
        
    # event_response = requests.get(f'{JANUS_URL}/{session_id}/events')
    # print(event_response.json(), "event_response-candiate")
    # ice_candidates = []
    
    # # Extract ICE candidates if available
    
    # for event in event_response.get('plugindata', {}).get('data', {}).get('candidates', []):
    #     ice_candidates.append(event)
    
    






# Handle Answer (send it to Janus)
@app.route('/send_answer', methods=['POST'])
def send_answer():
    data = request.json
    
    session_id = data['session_id']
    handle_id = data['handle_id']
    
    jsep = data['jsep']


    request_data = {
        "janus": "message",
        "body": { 
            "request": "start", 
            "room": roomId 
            },
        "jsep": jsep,
        "transaction": str(uuid.uuid4())
    }

    response = janus_event(f"{session_id}/{handle_id}", request_data)
    if response["janus"] == "ack":
        event_response = requests.get(f'{JANUS_URL}/{session_id}/events')
        print(event_response.json(), 'event_response-send-answer')
        
        return jsonify(event_response.json())
    
    return jsonify(response)




# 5️ Handle ICE Candidates
@app.route('/ice-candidate', methods=['POST'])
def ice_candidate():
    data = request.json
    candidate = data.get("candidate")
    user_id = data.get("user_id")
    session_id = data.get("session_id")
    handle_id = data.get("handle_id")
    

    payload = {
        "janus": "trickle",
        "transaction": str(uuid.uuid4()),
        "candidate": candidate
    }
    
    
    if not session_id or not handle_id:
        return jsonify({"error": "Session or Feed ID not found"}), 400

    response = janus_event(f"{session_id}/{handle_id}", payload)
    if response["janus"] != "ack":
        return jsonify({"error": "Ice-candidate is not configure by janus!!!"})
    
    event_response = requests.get(f'{JANUS_URL}/{session_id}/events')
    print(event_response.json(), 'event_response-ice-candidate')
    
    return jsonify(event_response.json())





@app.route("/janus-trickle", methods=["POST"])
def janus_trickle():
    """Handles JSEP Answer sent from frontend and forwards to Janus."""
    
    
    data = request.json
    user_id = data.get("user_id")
    session_id = sessions[user_id]["session_id"]
    handle_id = sessions[user_id]["handle_id"]
    # Get JSEP answer from frontend
    jsep = data.get("jsep")
    transaction_id = str(uuid.uuid4())

    if not jsep:
        return jsonify({"error": "Missing JSEP Answer"}), 400

    # Prepare the data to send to Janus
    data = {
        "janus": "message",
        "transaction": transaction_id,
        "body": {
            "request": "start",
            "room": roomId
        },
        "jsep": jsep  # Send JSEP answer
    }

    # Send the request to Janus
    response = requests.post(f"{JANUS_URL}/{session_id}/{handle_id}", json=data)
    
    if response.json()["janus"] != "ack":
        return jsonify({"error": "Janus tricle answer handling error!!!"})
    
    time.sleep(1)
    event_response = requests.get(f'{JANUS_URL}/{session_id}/events')
    print(event_response.json(), 'event_response-trickle')
    
    return jsonify(event_response.json())


# Store Host Id
def store_host_handle_id(handle_id):
    with open("hostfeed.txt", "w") as f:
        f.write(str(handle_id))
        
# Check Host Id
def is_host_id():
    status = True
    try:
        
        file_size = os.path.getsize("hostfeed.txt")
        if file_size == 0:
            status = False
        else:
            status = True
            
    except FileNotFoundError as e:
        status = False
        
    return status


# Get host id
def get_host_id():
    data = ""
    with open("hostfeed.txt", "r", encoding = "UTF-8") as f:
        data = f.read()
        
    return data







# Socket 


    
@socketio.on("offer")
def on_offer(data):
    
    emit("offer", data, broadcast=True, include_self=False)
    
@socketio.on("answer")
def on_answer(data):
    
    emit("answer", data, broadcast=True, include_self=False)
    
@socketio.on("ice-candidate")
def on_ice_candidate(data):
    
    emit("ice-candidate", data, broadcast=True, include_self=False)




if __name__ == '__main__':
    socketio.run(app, debug=True, host="0.0.0.0", port=5656)
