#!/usr/bin/env python3
"""
手机键盘控制电脑 - CLI 命令行界面
"""

import os
import socket
import click
from flask import Flask, send_from_directory, request
from flask_socketio import SocketIO
from pynput.keyboard import Controller, Key
from pynput.mouse import Controller as MouseController, Button


# 获取包所在目录
PACKAGE_DIR = os.path.dirname(os.path.abspath(__file__))

app = Flask(__name__, static_folder=PACKAGE_DIR)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app, cors_allowed_origins="*", async_mode='threading', transports=['polling', 'websocket'])

keyboard = Controller()
mouse = MouseController()


def get_local_ip():
    """获取本机局域网 IP 地址"""
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    try:
        s.connect(('10.255.255.255', 1))
        ip = s.getsockname()[0]
    except:
        ip = '127.0.0.1'
    finally:
        s.close()
    return ip


def get_all_ips():
    """获取所有网络接口的 IP 地址"""
    ips = []
    hostname = socket.gethostname()
    # 获取所有 IP
    try:
        addr_info = socket.getaddrinfo(hostname, None)
        for info in addr_info:
            ip = info[4][0]
            if ip != '127.0.0.1' and ':' not in ip:  # 排除 IPv6
                ips.append(ip)
    except:
        pass
    return ips


def print_banner(port):
    """打印终端图形横幅"""
    local_ip = get_local_ip()
    all_ips = get_all_ips()

    banner = f"""
\x1b[36m╔════════════════════════════════════════════════════════════════════════╗
\x1b[36m║                                                                        ║
\x1b[36m║      \x1b[33m╔═╗╔╦╗╦ ╦╔═╗╔═╗╦ ╦    ╔╦╗╦ ╦╔═╗╔═╗╔═╗╔═╗\x1b[0m\x1b[36m                              ║
\x1b[36m║      \x1b[33m║ ║ ║ ╠═╣╠═╝╠═╣╚╦╝     ║ ║ ║╠─╣╠╣ ║ ║║ ╦\x1b[0m\x1b[36m   \x1b[32m屏幕键盘控制电脑\x1b[0m\x1b[36m           ║
\x1b[36m║      \x1b[33m╚═╝ ╩ ╩ ╩╩  ╩ ╩ ╩      ╩ ╚═╝╩ ╩╚═╝╚═╝╚═╝\x1b[0m\x1b[36m   \x1b[32mScreen Keyboard\x1b[0m\x1b[36m           ║
\x1b[36m║                                                                        ║
\x1b[36m╠════════════════════════════════════════════════════════════════════════╣
\x1b[36m║  \x1b[32m🚀 服务已启动                                                     \x1b[36m  ║
\x1b[36m╠════════════════════════════════════════════════════════════════════════╣
\x1b[36m║  \x1b[37m📱 局域网地址：                                                    \x1b[36m  ║
\x1b[36m║  \x1b[33m➜  http://{local_ip}:{port:<35}\x1b[36m  ║
"""

    # 添加其他 IP 地址
    other_ips = [ip for ip in all_ips if ip != local_ip and ip != '127.0.1.1']
    if other_ips:
        banner += f"\x1b[36m║  \x1b[37m📍 其他地址：                                                      \x1b[36m  ║\x1b[0m\n"
        for ip in other_ips[:3]:  # 最多显示 3 个
            banner += f"\x1b[36m║  \x1b[33m   http://{ip}:{port:<33}\x1b[36m  ║\x1b[0m\n"

    banner += f"""
\x1b[36m╠════════════════════════════════════════════════════════════════════════╣
\x1b[36m║  \x1b[35m🔗 请在手机浏览器访问上述地址                                      \x1b[36m  ║
\x1b[36m║  \x1b[35m⏹️  按 Ctrl+C 停止服务                                                \x1b[36m  ║
\x1b[36m╚════════════════════════════════════════════════════════════════════════╝\x1b[0m
"""
    click.echo(banner)


@app.route('/')
def index():
    return send_from_directory(PACKAGE_DIR, 'index.html')


@socketio.on('connect')
def handle_connect():
    click.echo(f"\x1b[32m[连接] 客户端已连接：{request.sid}\x1b[0m")


@socketio.on('disconnect')
def handle_disconnect():
    click.echo(f"\x1b[31m[断开] 客户端已断开：{request.sid}\x1b[0m")


@socketio.on('key')
def handle_key(data):
    """处理键盘按键事件"""
    key = data.get('key', '')
    key_type = data.get('type', 'char')

    if key_type == 'special':
        if not handle_special_key(key):
            click.echo(f"\x1b[33m[警告] 未知特殊键：{key}\x1b[0m")
    else:
        keyboard.type(key)


@socketio.on('key_combo')
def handle_key_combo(data):
    """处理组合键"""
    key = data.get('key', '')
    ctrl = data.get('ctrl', False)
    ctrl_right = data.get('ctrl_right', False)
    alt = data.get('alt', False)
    alt_right = data.get('alt_right', False)
    win = data.get('win', False)
    shift = data.get('shift', False)
    shift_right = data.get('shift_right', False)

    modifiers = []
    if ctrl:
        modifiers.append(Key.ctrl)
    if ctrl_right:
        modifiers.append(Key.ctrl_r)
    if alt:
        modifiers.append(Key.alt)
    if alt_right:
        modifiers.append(Key.alt_r)
    if win:
        modifiers.append(Key.cmd)
    if shift:
        modifiers.append(Key.shift)
    if shift_right:
        modifiers.append(Key.shift_r)

    for mod in modifiers:
        keyboard.press(mod)

    if len(key) == 1:
        keyboard.press(key.lower())
        keyboard.release(key.lower())
    else:
        handle_special_key(key)

    for mod in reversed(modifiers):
        keyboard.release(mod)


@socketio.on('mouse_move')
def handle_mouse_move(data):
    """处理鼠标移动"""
    x = data.get('x', 0)
    y = data.get('y', 0)
    mouse.move(x, y)


@socketio.on('mouse_click')
def handle_mouse_click(data):
    """处理鼠标点击"""
    button = data.get('button', 'left')
    if button == 'left':
        mouse.click(Button.left)
    elif button == 'right':
        mouse.click(Button.right)
    elif button == 'middle':
        mouse.click(Button.middle)


@socketio.on('mouse_press')
def handle_mouse_press(data):
    """处理鼠标按键按下/释放"""
    button = data.get('button', 'left')
    pressed = data.get('pressed', True)
    if button == 'left':
        if pressed:
            mouse.press(Button.left)
        else:
            mouse.release(Button.left)
    elif button == 'right':
        if pressed:
            mouse.press(Button.right)
        else:
            mouse.release(Button.right)
    elif button == 'middle':
        if pressed:
            mouse.press(Button.middle)
        else:
            mouse.release(Button.middle)


@socketio.on('mouse_scroll')
def handle_mouse_scroll(data):
    """处理鼠标滚轮"""
    direction = data.get('direction', 'up')
    if direction == 'up':
        mouse.scroll(0, 3)
    else:
        mouse.scroll(0, -3)


def handle_special_key(key):
    """处理特殊按键"""
    key_map = {
        'Enter': Key.enter,
        'Backspace': Key.backspace,
        'Space': Key.space,
        'Tab': Key.tab,
        'Escape': Key.esc,
        'CapsLock': Key.caps_lock,
        'Ctrl': Key.ctrl,
        'CtrlRight': Key.ctrl_r,
        'Alt': Key.alt,
        'AltRight': Key.alt_r,
        'Shift': Key.shift,
        'ShiftRight': Key.shift_r,
        'Super': Key.cmd,
        'SuperRight': Key.cmd_r,
        'Menu': Key.menu,
        'ArrowUp': Key.up,
        'ArrowDown': Key.down,
        'ArrowLeft': Key.left,
        'ArrowRight': Key.right,
        'Insert': Key.insert,
        'Delete': Key.delete,
        'Home': Key.home,
        'End': Key.end,
        'PageUp': Key.page_up,
        'PageDown': Key.page_down,
        'F1': Key.f1,
        'F2': Key.f2,
        'F3': Key.f3,
        'F4': Key.f4,
        'F5': Key.f5,
        'F6': Key.f6,
        'F7': Key.f7,
        'F8': Key.f8,
        'F9': Key.f9,
        'F10': Key.f10,
        'F11': Key.f11,
        'F12': Key.f12,
        'PrintScreen': Key.print_screen,
        'ScrollLock': Key.scroll_lock,
        'Pause': Key.pause,
    }

    if key in key_map:
        keyboard.press(key_map[key])
        keyboard.release(key_map[key])
        return True
    return False


def run_server(port, host):
    """运行服务器"""
    print_banner(port)
    socketio.run(app, host=host, port=port, debug=False, allow_unsafe_werkzeug=True)


@click.group()
@click.version_option(version='1.0.1', prog_name='screen-keyboard')
def cli():
    """📱 手机键盘控制电脑 - 通过手机浏览器控制电脑输入"""
    pass


@cli.command()
@click.option('--port', '-p', default=5000, help='服务端口 (默认：5000)')
@click.option('--host', '-h', default='0.0.0.0', help='监听地址 (默认：0.0.0.0)')
def start(port, host):
    """🚀 启动服务

    在手机浏览器访问显示的地址即可开始使用。
    """
    run_server(port, host)


@cli.command()
def info():
    """ℹ️  查看本机网络信息

    显示所有可用的网络接口和 IP 地址。
    """
    local_ip = get_local_ip()
    all_ips = get_all_ips()
    hostname = socket.gethostname()

    click.echo(f"""
\x1b[36m╔════════════════════════════════════════════╗
\x1b[36m║  \x1b[37m本机网络信息                           \x1b[36m║
\x1b[36m╠════════════════════════════════════════════╣
\x1b[36m║  \x1b[37m主机名：\x1b[33m{hostname:<29}\x1b[36m║
\x1b[36m║  \x1b[37m主 IP 地址：\x1b[33m{local_ip:<27}\x1b[36m║
\x1b[36m╠════════════════════════════════════════════╣
\x1b[36m║  \x1b[37m所有可用 IP 地址：                       \x1b[36m║\x1b[0m""")

    for ip in all_ips:
        click.echo(f"\x1b[36m║  \x1b[33m  • {ip:<32}\x1b[36m║\x1b[0m")

    click.echo(f"""
\x1b[36m╠════════════════════════════════════════════╣
\x1b[36m║  \x1b[37m使用示例：                              \x1b[36m║
\x1b[36m║  \x1b[37mscreen-keyboard start --port 5000       \x1b[36m║
\x1b[36m║  \x1b[37mscreen-keyboard start -p 8080           \x1b[36m║
\x1b[36m╚════════════════════════════════════════════╝\x1b[0m
""")


@cli.command()
def ip():
    """🌐 快速查看局域网 IP

    只显示主要局域网 IP 地址，方便快速访问。
    """
    local_ip = get_local_ip()
    click.echo(f"\n\x1b[32m局域网 IP: \x1b[33m{local_ip}\x1b[0m\n")
    click.echo(f"访问地址：\x1b[36mhttp://{local_ip}:5000\x1b[0m\n")


@cli.command()
@click.option('--port', '-p', default=5000, help='要检查的端口')
def check(port):
    """🔍 检查端口是否被占用

    检查指定端口是否可用。
    """
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    result = sock.connect_ex(('0.0.0.0', port))
    sock.close()

    if result == 0:
        click.echo(f"\x1b[31m✗ 端口 {port} 已被占用\x1b[0m")
        return False
    else:
        click.echo(f"\x1b[32m✓ 端口 {port} 可用\x1b[0m")
        return True


@cli.command()
def help():
    """❓ 显示帮助信息"""
    click.echo("""
\x1b[36m╔══════════════════════════════════════════════════════════╗
\x1b[36m║                                                      \x1b[0m\x1b[33m▄▀█║
\x1b[36m║  \x1b[32m手机键盘控制电脑 - 命令行帮助                        \x1b[0m\x1b[33m█║
\x1b[36m║                                                      \x1b[0m\x1b[33m█║
\x1b[36m╠══════════════════════════════════════════════════════════╣
\x1b[36m║  \x1b[37m可用命令：                                            \x1b[36m║
\x1b[36m╠══════════════════════════════════════════════════════════╣
\x1b[36m║  \x1b[33mstart\x1b[37m     启动服务 (可指定 --port)               \x1b[36m║
\x1b[36m║  \x1b[33minfo\x1b[37m      查看本机网络信息                          \x1b[36m║
\x1b[36m║  \x1b[33mip\x1b[37m        快速查看局域网 IP                        \x1b[36m║
\x1b[36m║  \x1b[33mcheck\x1b[37m     检查端口是否被占用                       \x1b[36m║
\x1b[36m║  \x1b[33mhelp\x1b[37m      显示此帮助信息                           \x1b[36m║
\x1b[36m╠══════════════════════════════════════════════════════════╣
\x1b[36m║  \x1b[37m使用示例：                                            \x1b[36m║
\x1b[36m║  \x1b[37mscreen-keyboard start          # 使用默认端口 5000     \x1b[36m║
\x1b[36m║  \x1b[37mscreen-keyboard start -p 8080  # 使用端口 8080        \x1b[36m║
\x1b[36m║  \x1b[37mscreen-keyboard ip             # 查看 IP 地址          \x1b[36m║
\x1b[36m║  \x1b[37mscreen-keyboard info           # 查看所有网络信息    \x1b[36m║
\x1b[36m║  \x1b[37mscreen-keyboard check -p 5000  # 检查端口 5000       \x1b[36m║
\x1b[36m╚══════════════════════════════════════════════════════════╝\x1b[0m
""")


# 兼容旧版本的 main 函数
def main():
    """命令行入口（旧版，兼容用）"""
    cli()


if __name__ == '__main__':
    cli()
