import sys
import time
import threading
import json
from datetime import datetime, timezone
from loguru import logger

from gitchat.core import git, git_output, push_message
from gitchat.utils import encrypt_aes, decrypt_aes


class Chat:
    def __init__(
        self, username: str, delay: float = 1.0, handler=None, password=None, cwd="."
    ):
        self.username = username
        self.delay = delay
        self.handler = handler
        self.password = password
        self.cwd = cwd
        self.last_seen: dict[str, int] = {}
        self.stop_event = threading.Event()
        self.fetcher_thread = None

    def fetch_and_process(self):
        """Run git fetch and display new messages from other branches."""
        git("fetch", "origin", cwd=self.cwd, check=False)

        branches = git_output("branch", "-r", cwd=self.cwd)
        if not branches:
            return
        # Parse branch names (ex. origin/user)
        remote_branches = [
            b.strip()
            for b in branches.splitlines()
            if b.strip() and not b.strip().endswith("HEAD")
        ]
        for full_branch in remote_branches:
            if not full_branch.startswith("origin/"):
                continue
            branch = full_branch.split("/", 1)[1]
            # Skip own branch
            if branch == self.username:
                continue

            messages = []
            try:
                content = git_output(
                    "show", f"{full_branch}:{branch}.json", cwd=self.cwd
                )
                if not content:
                    continue
                messages = json.loads(content)
            except Exception as e:
                logger.error(f"Failed to read new messages: {e}")
                continue

            # Determine new messages
            now = datetime.now(timezone.utc).timestamp()
            seen = self.last_seen.get(branch, 0)
            if len(messages) > seen:
                for i in range(seen, len(messages)):
                    if self.password:
                        try:
                            messages[i]["data"] = decrypt_aes(
                                messages[i]["data"], self.password
                            )
                        except Exception as e:
                            logger.error(
                                f"Failed to decrypt message (bad password or not encrypted): {e}"
                            )
                    
                    # Push message to handler
                    if self.handler:
                        try:
                            self.handler(messages[i])
                        except Exception as e:
                            logger.error(f"Failed to push message to handler: {e}")
                    # Logging message
                    logger.info(f"[{branch}] {messages[i]["data"]}")
                self.last_seen[branch] = len(messages)

    def fetcher_loop(self):
        """Periodically fetches and prints messages"""
        while not self.stop_event.is_set():
            self.fetch_and_process()
            time.sleep(self.delay)

    def send_msg(self, message: str):
        """Sends message to chat"""
        if not message:
            logger.debug("Tried to send empty message, ignore ...")
            return
        message = message.strip()
        if message:
            if self.password:
                try:
                    message = encrypt_aes(message, self.password)
                except Exception as e:
                    logger.error(f"Failed to encrypt message: {e}")
                    return
            push_message(self.username, message, cwd=self.cwd)
            logger.debug(f"Message sent from `{self.username}`")

    def send_loop(self):
        """Read stdin and send messages"""
        logger.debug(
            f"Chat started as `{self.username}`. Type messages and press Enter. Ctrl+C to exit."
        )
        while not self.stop_event.is_set():
            try:
                line = sys.stdin.readline()
                if not line:
                    break
                text = line.strip()
                if text:
                    if self.password:
                        try:
                            text = encrypt_aes(text, self.password)
                        except Exception as e:
                            logger.error(f"Failed to encrypt message: {e}")
                    push_message(self.username, text, cwd=self.cwd)
            except Exception as e:
                logger.error(f"Error sending message: {e}")

    def start(self):
        """Entrypoint for chat"""
        self.fetcher_thread = threading.Thread(target=self.fetcher_loop, daemon=True)
        self.fetcher_thread.start()
        try:
            self.send_loop()
        except KeyboardInterrupt:
            print("\nExiting...")
        finally:
            self.stop_event.set()
            if self.fetcher_thread.is_alive():
                self.fetcher_thread.join(timeout=2)
