from flask import Flask, render_template
from flask_socketio import SocketIO, emit
import ssl
import os

app = Flask(__name__, static_folder='static', template_folder='templates')
app.config['SECRET_KEY'] = 'your-secret-key-change-this-in-production'
socketio = SocketIO(app, cors_allowed_origins="*")

# Store connected clients with their usernames
connected_clients = {}  # Format: {session_id: {'username': 'name', 'connected_at': timestamp}}

@app.route('/')
def index():
    return render_template('index.html')

@socketio.on('connect')
def handle_connect(auth):
    from flask import request
    print(f'Client connected: {request.sid}')  # type: ignore
    connected_clients[request.sid] = {'username': None, 'connected_at': None}  # type: ignore

@socketio.on('disconnect')
def handle_disconnect():
    from flask import request  
    print(f'Client disconnected: {request.sid}')  # type: ignore
    
    username = None
    if request.sid in connected_clients:  # type: ignore
        username = connected_clients[request.sid].get('username')  # type: ignore
        del connected_clients[request.sid]  # type: ignore
    
    # Notify other clients about disconnection
    emit('user_disconnected', {'id': request.sid}, broadcast=True, include_self=False)  # type: ignore
    
    # Notify chat about user leaving
    if username:
        emit('user_left_chat', {'username': username}, broadcast=True, include_self=False)

@socketio.on('offer')
def handle_offer(data):
    from flask import request
    print(f'Received offer from {request.sid}')  # type: ignore
    # Broadcast offer to all other clients
    data['id'] = request.sid  # type: ignore
    emit('offer', data, broadcast=True, include_self=False)

@socketio.on('answer')
def handle_answer(data):
    from flask import request
    print(f'Received answer from {request.sid}')  # type: ignore
    # Send answer to specific client
    emit('answer', data, to=data['id'])

@socketio.on('ice_candidate')
def handle_ice_candidate(data):
    from flask import request
    print(f'Received ICE candidate from {request.sid}')  # type: ignore
    # Add sender ID to the data and send to target
    data['id'] = request.sid  # type: ignore
    if 'target_id' in data:
        emit('ice_candidate', data, to=data['target_id'])
    else:
        emit('ice_candidate', data, broadcast=True, include_self=False)

@socketio.on('join_room')
def handle_join_room(data=None):
    from flask import request
    username = data.get('username', 'Anonymous') if data else 'Anonymous'
    print(f'Client {request.sid} ({username}) joining room')  # type: ignore
    
    # Update client info with username
    if request.sid in connected_clients:  # type: ignore
        connected_clients[request.sid]['username'] = username  # type: ignore
        connected_clients[request.sid]['connected_at'] = __import__('time').time()  # type: ignore
    
    # Get list of existing users with usernames (excluding the new user)
    existing_users = []
    for user_id, user_info in connected_clients.items():
        if user_id != request.sid and user_info['username']:  # type: ignore
            existing_users.append({
                'id': user_id,
                'username': user_info['username']
            })
    
    # Send existing users list to the new user
    if existing_users:
        emit('existing_users', {'users': existing_users})
    
    # Notify existing clients about new user
    emit('user_joined', {
        'id': request.sid,  # type: ignore
        'username': username
    }, broadcast=True, include_self=False)
    
    # Notify chat about new user
    emit('user_joined_chat', {
        'username': username
    }, broadcast=True, include_self=False)

@socketio.on('chat_message')
def handle_chat_message(data):
    from flask import request
    print(f'Chat message from {request.sid} ({data.get("username", "Unknown")}): {data.get("message", "")}')  # type: ignore
    
    # Broadcast message to all other clients (sender already displayed it locally)
    emit('chat_message', {
        'username': data.get('username', 'Unknown'),
        'message': data.get('message', ''),
        'timestamp': data.get('timestamp', __import__('time').time() * 1000),
        'sender_id': request.sid  # type: ignore
    }, broadcast=True, include_self=False)

if __name__ == '__main__':
    # Set up SSL context
    context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
    context.load_cert_chain('cert.pem', 'key.pem')
    
    print("Starting Flask-SocketIO server on https://localhost:3232")
    socketio.run(app, host='0.0.0.0', port=3232, ssl_context=context, debug=True)
