"""Bridge monop binary to IRC via subprocess pipes."""

import sys
sys.stdout.reconfigure(line_buffering=True)

import socket
import subprocess
import threading
import time
import sys
import os
import re

HOST = "127.0.0.1"
PORT = 6667
NICK = "monop"
CHANNEL = "#monop"
PREFIX = "."
MONOP_BIN = "/tmp/monop-irc/monop/monop"
CARDS_FILE = "/tmp/monop-irc/monop/cards.pck"


class IRCBridge:
    def __init__(self):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.proc = None
        self.buffer = ""

    def irc_send(self, line):
        self.sock.sendall((line + "\r\n").encode())

    def irc_say(self, msg):
        self.irc_send(f"PRIVMSG {CHANNEL} :{msg}")

    def connect_irc(self):
        self.sock.connect((HOST, PORT))
        self.irc_send(f"NICK {NICK}")
        self.irc_send(f"USER {NICK} 0 * :{NICK}")
        # Wait for registration
        while True:
            data = self.sock.recv(4096)
            if not data:
                raise ConnectionError("IRC connection closed during registration")
            self.buffer += data.decode("utf-8", errors="replace")
            for line in self.buffer.split("\r\n"):
                if line.startswith("PING"):
                    self.irc_send("PONG" + line[4:])
                if "ERROR" in line:
                    print(f"[bridge] Server error: {line}")
            if " 001 " in self.buffer:
                break
        self.irc_send(f"JOIN {CHANNEL}")
        time.sleep(0.5)
        self.buffer = ""
        self.irc_say("Shall We Play A Game?")
        self.irc_say(f'Prefix your commands with a dot "."')
        print(f"[bridge] Connected to IRC as {NICK} in {CHANNEL}")

    def start_monop(self):
        env = os.environ.copy()
        self.proc = subprocess.Popen(
            [MONOP_BIN],
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
            env=env,
            cwd=os.path.dirname(MONOP_BIN),
        )
        # Read monop stdout -> IRC
        t = threading.Thread(target=self._monop_reader, daemon=True)
        t.start()
        print("[bridge] monop process started")

    def _monop_reader(self):
        """Read lines from monop stdout and send to IRC."""
        for raw in self.proc.stdout:
            line = raw.decode("utf-8", errors="replace").rstrip("\n\r")
            if line:
                self.irc_say(line)
                print(f"[monop -> irc] {line}")

    def _feed_monop(self, nick, text):
        """Feed input to monop stdin as 'nick text'."""
        feed = f"{nick} {text}\n"
        print(f"[irc -> monop] {feed.rstrip()}")
        try:
            self.proc.stdin.write(feed.encode())
            self.proc.stdin.flush()
        except BrokenPipeError:
            print("[bridge] monop process died, restarting...")
            self.start_monop()

    def _wait_for_players(self):
        """Wait until at least one other user joins the channel before starting."""
        print(f"[bridge] Waiting for players to join {CHANNEL}...")
        while True:
            data = self.sock.recv(4096)
            if not data:
                raise ConnectionError("IRC connection lost while waiting")
            self.buffer += data.decode("utf-8", errors="replace")
            while "\r\n" in self.buffer:
                line, self.buffer = self.buffer.split("\r\n", 1)
                if line.startswith("PING"):
                    self.irc_send("PONG" + line[4:])
                # Detect JOIN from someone other than us
                m = re.match(r":(\S+?)!\S+ JOIN", line)
                if m and m.group(1) != NICK:
                    print(f"[bridge] {m.group(1)} joined — starting game")
                    return

    def _process_buffer(self):
        """Process any complete lines in the buffer."""
        while "\r\n" in self.buffer:
            line, self.buffer = self.buffer.split("\r\n", 1)
            if line.startswith("PING"):
                self.irc_send("PONG" + line[4:])
                continue
            m = re.match(r":(\S+?)!(\S+?) PRIVMSG (\S+) :(.+)", line)
            if m:
                sender_nick = m.group(1)
                target = m.group(3)
                msg = m.group(4)
                if target == CHANNEL and sender_nick != NICK:
                    if msg.startswith(PREFIX):
                        cmd = msg[len(PREFIX):]
                        self._feed_monop(sender_nick, cmd)

    def run(self):
        self.connect_irc()
        self._wait_for_players()
        self.start_monop()

        # Process any lines buffered during _wait_for_players
        self._process_buffer()

        while True:
            try:
                data = self.sock.recv(4096)
                if not data:
                    break
                self.buffer += data.decode("utf-8", errors="replace")
                self._process_buffer()
            except Exception as e:
                print(f"[bridge] error: {e}")
                break


if __name__ == "__main__":
    bridge = IRCBridge()
    bridge.run()
