from datetime import datetime
from threading import Lock

from flask import Flask, render_template, request, jsonify
from flask_socketio import SocketIO, emit

app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key_here'
socketio = SocketIO(app, cors_allowed_origins="*", async_mode='threading')

# 存储客户端信息
clients = {}  # 格式: {client_id: client_info}
socket_to_client = {}  # 映射: socket_sid -> client_id
client_lock = Lock()
terminal_sessions = {}
pending_connections = {}  # 等待终端连接的请求


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


@app.route('/clients')
def get_clients():
    """获取客户端列表"""
    with client_lock:
        clients_list = [{
            'id': client_id,
            'name': info.get('name', 'Unknown'),
            'connected_at': info.get('connected_at'),
            'status': 'connected',
            'os': info.get('os')
        } for client_id, info in clients.items()]
    return jsonify(clients_list)


@socketio.on('client_register')
def handle_client_register(data):
    """客户端注册"""
    client_id = data.get('client_id')
    client_name = data.get('name', 'Unknown Client')
    client_os = data.get('os', 'Unknown Client')

    print(f"Client registering: {client_name} with ID: {client_id}")

    with client_lock:
        # 存储客户端信息
        clients[client_id] = {
            'id': client_id,
            'name': client_name,
            'connected_at': datetime.now().isoformat(),
            'socket_sid': request.sid,
            'type': 'client',
            'os': client_os
        }
        # 建立socket_sid到client_id的映射
        socket_to_client[request.sid] = client_id

    print(f"Client registered successfully: {client_name} (ID: {client_id})")
    print(f"Current clients: {list(clients.keys())}")

    emit('registration_success', {'status': 'registered'})

    # 检查是否有等待此客户端的终端连接请求
    if client_id in pending_connections:
        for frontend_sid in pending_connections[client_id]:
            start_terminal_session(client_id, frontend_sid)
        del pending_connections[client_id]

    # 广播客户端列表更新
    emit('clients_updated', broadcast=True)


def start_terminal_session(client_id, frontend_sid):
    """启动终端会话"""
    if client_id not in clients:
        return False

    # 建立终端会话映射
    terminal_sessions[client_id] = {
        'frontend_sid': frontend_sid,
        'client_sid': clients[client_id]['socket_sid']
    }

    # 通知前端终端已启动
    socketio.emit('terminal_started', {
        'client_id': client_id
    }, room=frontend_sid)

    print(f"Terminal session started for client: {client_id}")
    return True


@socketio.on('terminal_data')
def handle_terminal_data(data):
    """处理终端数据转发"""
    client_id = data.get('client_id')
    output = data.get('data')

    # 将客户端终端的输出转发给前端
    if client_id in terminal_sessions:
        emit('terminal_output', {
            'data': output,
            'client_id': client_id
        }, room=terminal_sessions[client_id]['frontend_sid'])


@socketio.on('frontend_connect')
def handle_frontend_connect():
    """前端连接"""
    print("Frontend connected")


@socketio.on('start_terminal')
def handle_start_terminal(data):
    """启动终端会话"""
    client_id = data.get('client_id')
    frontend_sid = request.sid

    print(f"Starting terminal for client: {client_id}")
    print(f"Available clients: {list(clients.keys())}")

    # 检查客户端是否存在
    if client_id in clients:
        # 客户端已注册，直接启动终端会话
        if start_terminal_session(client_id, frontend_sid):
            emit('terminal_status', {
                'status': 'connected',
                'client_id': client_id,
                'message': '终端连接已建立'
            })
        else:
            emit('terminal_error', {'error': '无法启动终端会话'})
    else:
        # 客户端尚未注册，将请求加入等待队列
        with client_lock:
            if client_id not in pending_connections:
                pending_connections[client_id] = []
            pending_connections[client_id].append(frontend_sid)

        emit('terminal_status', {
            'status': 'waiting',
            'client_id': client_id,
            'message': '等待客户端连接...'
        })
        print(f"Waiting for client {client_id} to register")


@socketio.on('terminal_input')
def handle_terminal_input(data):
    """处理前端终端输入"""
    client_id = data.get('client_id')
    input_data = data.get('data')

    # 将前端的输入转发给对应的客户端
    if client_id in terminal_sessions:
        client_sid = terminal_sessions[client_id]['client_sid']
        emit('terminal_command', {
            'command': input_data,
            'client_id': client_id
        }, room=client_sid)


@socketio.on('disconnect')
def handle_disconnect():
    """处理连接断开"""
    print(f"Client disconnected: {request.sid}")

    with client_lock:
        # 如果是客户端断开连接
        if request.sid in socket_to_client:
            client_id = socket_to_client[request.sid]

            # 清理客户端信息
            if client_id in clients:
                clients.pop(client_id)

            socket_to_client.pop(request.sid)

            # 清理终端会话
            if client_id in terminal_sessions:
                terminal_sessions.pop(client_id)

            print(f"Removed client: {client_id}")

        # 如果是前端断开连接，清理对应的终端会话
        for client_id in list(terminal_sessions.keys()):
            if terminal_sessions[client_id]['frontend_sid'] == request.sid:
                terminal_sessions.pop(client_id)
                print(f"Removed terminal session for client: {client_id}")

        # 清理等待队列中的前端请求
        for client_id in list(pending_connections.keys()):
            if request.sid in pending_connections[client_id]:
                pending_connections[client_id].remove(request.sid)
                if not pending_connections[client_id]:
                    del pending_connections[client_id]

    emit('clients_updated', broadcast=True)


def start():
    socketio.run(app, host='0.0.0.0', port=5000, debug=True, allow_unsafe_werkzeug=True)


if __name__ == '__main__':
    start()
