from flask_socketio import emit, join_room, leave_room
from flask import request
from .omok_state import rooms
from datetime import datetime
import random

def register_omok_events(socketio):
    # (1) 방 목록 요청
    @socketio.on("get_room_list")
    def get_room_list():
        room_list = [
            {
                "room_id": room_id,
                "players": len(data["players"]),
                "created_at": data["created_at"].strftime("%Y-%m-%d %H:%M:%S")
            }
            for room_id, data in rooms.items()
        ]
        emit("room_list", room_list, room=request.sid)

    # (2) 방 참여
    @socketio.on("join")
    def on_join(data):
        room = data["room"]
        uuid = data.get("uuid")
        nickname = data.get("nickname", f"User{uuid[:6]}")
        sid = request.sid

        if room not in rooms:
            # 방 생성
            rooms[room] = {
                "created_at": datetime.now(),
                "board": [[0]*15 for _ in range(15)],
                "players": {},
                "spectators": {},
                "turn": 1,
                "owner_uuid": uuid,
                "game_ended": False
            }

        room_data = rooms[room]
        join_room(room)

        # 참가자 or 관전자 처리
        if uuid in room_data["players"]:
            room_data["players"][uuid]["sid"] = sid
        elif len(room_data["players"]) < 2:
            assigned = 1 if 1 not in [p["player"] for p in room_data["players"].values()] else 2
            room_data["players"][uuid] = {
                "sid": sid,
                "nickname": nickname,
                "player": assigned
            }
        else:
            room_data["spectators"][uuid] = {"sid": sid, "nickname": nickname}

        # 응답 전송
        players_list = [
            f'{p["nickname"]} ({"흑" if p["player"] == 1 else "백"})'
            for p in room_data["players"].values()
        ]
        emit("joined", {
            "board": room_data["board"],
            "players": players_list,
            "your_player": room_data["players"].get(uuid, {}).get("player", 0),
            "turn": room_data["turn"]
        }, room=sid)
        emit("update_players", {"players": players_list}, room=room)

    # (3) 착수 처리
    @socketio.on("move")
    def on_move(data):
        room = data["room"]
        x, y = data["x"], data["y"]
        sid = request.sid
        room_data = rooms.get(room)

        if not room_data or room_data["game_ended"]:
            return

        uuid = next((uid for uid, p in room_data["players"].items() if p["sid"] == sid), None)
        if not uuid:
            return

        player_num = room_data["players"][uuid]["player"]
        if player_num != room_data["turn"]:
            return

        if room_data["board"][y][x] == 0:
            room_data["board"][y][x] = player_num
            room_data["turn"] = 3 - player_num
            emit("update", {"x": x, "y": y, "player": player_num}, room=room)

            # 승리 여부 체크
            if check_win(room_data["board"], x, y, player_num):
                room_data["game_ended"] = True
                emit("game_over", {"winner": player_num, "x": x, "y": y}, room=room)

    # (4) 기권 처리
    @socketio.on("surrender")
    def on_surrender(data):
        room = data["room"]
        sid = request.sid
        room_data = rooms.get(room)
        if not room_data:
            return
        uuid = next((uid for uid, p in room_data["players"].items() if p["sid"] == sid), None)
        if not uuid:
            return
        loser = room_data["players"][uuid]["player"]
        winner = 3 - loser
        room_data["game_ended"] = True
        emit("game_over", {"winner": winner, "surrender": True}, room=room)

    # (5) 재대결 요청
    @socketio.on("rematch_request")
    def rematch_request(data):
        room = data["room"]
        sid = request.sid
        for player in rooms[room]["players"].values():
            if player["sid"] != sid:
                emit("rematch_confirm", {}, room=player["sid"])
            else:
                emit("rematch_waiting", {}, room=player["sid"])

    @socketio.on("rematch_accept")
    def rematch_accept(data):
        room = data["room"]
        if room in rooms:
            rooms[room]["board"] = [[0]*15 for _ in range(15)]
            rooms[room]["turn"] = 1
            rooms[room]["game_ended"] = False
            emit("reset_board", {"board": rooms[room]["board"]}, room=room)

    @socketio.on("rematch_decline")
    def rematch_decline(data):
        room = data["room"]
        emit("rematch_denied", {}, room=room)

    # (6) 초기화 요청
    @socketio.on("request_reset")
    def request_reset(data):
        room = data["room"]
        sender = request.sid
        room_data = rooms.get(room)
        if not room_data:
            return
        for player in room_data["players"].values():
            if player["sid"] != sender:
                emit("confirm_reset", {}, room=player["sid"])
            else:
                emit("reset_requested", {}, room=player["sid"])

    @socketio.on("accept_reset")
    def accept_reset(data):
        room = data["room"]
        if room in rooms:
            rooms[room]["board"] = [[0]*15 for _ in range(15)]
            rooms[room]["turn"] = 1
            emit("reset_board", {"board": rooms[room]["board"]}, room=room)

    # (7) 연결 해제
    @socketio.on("disconnect")
    def on_disconnect():
        sid = request.sid
        for room_id, room in list(rooms.items()):
            found = False
            for group in ["players", "spectators"]:
                for uuid, user in list(room[group].items()):
                    if user["sid"] == sid:
                        del room[group][uuid]
                        found = True
                        break
                if found:
                    break

            # 방장이 나갔고 참가자가 없으면 방 삭제
            if not room["players"] and room["owner_uuid"]:
                emit("room_closed", {}, room=room_id)
                del rooms[room_id]

# (8) 5목 체크 함수
def check_win(board, x, y, player):
    for dx, dy in [(1, 0), (0, 1), (1, 1), (1, -1)]:
        count = 1
        for dir in [1, -1]:
            nx, ny = x, y
            while True:
                nx += dx * dir
                ny += dy * dir
                if 0 <= nx < 15 and 0 <= ny < 15 and board[ny][nx] == player:
                    count += 1
                else:
                    break
        if count >= 5:
            return True
    return False
