"""Environment data for cheatly - simple, explicit data gathering."""

import os
import subprocess
from dataclasses import dataclass
from pathlib import Path


@dataclass
class Environment:
    """All environment data in one place.

    Attributes:
        terminal_size: Terminal dimensions (columns, lines)
        tmux_session: TMUX environment variable value if in tmux
        pane_id: Tmux pane identifier
        pane_command: Command running in the pane
        pane_pwd: Working directory of the pane
        working_dir: Current working directory
        shell: User's shell from SHELL environment variable
    """

    terminal_size: tuple[int, int]
    tmux_session: str | None = None
    pane_id: str | None = None
    pane_command: str | None = None
    pane_pwd: Path | None = None
    working_dir: Path = Path.cwd()
    shell: str | None = None

    @classmethod
    def from_system(cls, pane_id: str | None = None) -> "Environment":
        """Gather environment from current system.

        Args:
            pane_id: Optional specific pane to inspect

        Returns:
            Environment with all available data
        """
        import shutil

        size = shutil.get_terminal_size()
        terminal_size = (size.columns, size.lines)

        tmux_session = os.environ.get("TMUX")

        if tmux_session and not pane_id:
            pane_id = cls._get_current_pane()

        pane_command = None
        pane_pwd = None
        if pane_id:
            pane_command = cls._get_pane_command(pane_id)
            pane_pwd_str = cls._get_pane_pwd(pane_id)
            if pane_pwd_str:
                pane_pwd = Path(pane_pwd_str)

        shell = os.environ.get("SHELL")

        return cls(
            terminal_size=terminal_size,
            tmux_session=tmux_session,
            pane_id=pane_id,
            pane_command=pane_command,
            pane_pwd=pane_pwd,
            working_dir=Path.cwd(),
            shell=shell,
        )

    @staticmethod
    def _get_current_pane() -> str | None:
        """Get current tmux pane ID."""
        try:
            result = subprocess.check_output(
                ["tmux", "display-message", "-p", "#{pane_id}"],
                text=True,
                stderr=subprocess.DEVNULL,
            ).strip()
            return result
        except (subprocess.CalledProcessError, FileNotFoundError):
            return None

    @staticmethod
    def _get_pane_command(pane_id: str) -> str | None:
        """Get command running in pane."""
        try:
            result = subprocess.check_output(
                [
                    "tmux",
                    "display-message",
                    "-t",
                    pane_id,
                    "-p",
                    "#{pane_current_command}",
                ],
                text=True,
                stderr=subprocess.DEVNULL,
            ).strip()
            return result
        except (subprocess.CalledProcessError, FileNotFoundError):
            return None

    @staticmethod
    def _get_pane_pwd(pane_id: str) -> str | None:
        """Get working directory of pane."""
        try:
            result = subprocess.check_output(
                [
                    "tmux",
                    "display-message",
                    "-t",
                    pane_id,
                    "-p",
                    "#{pane_current_path}",
                ],
                text=True,
                stderr=subprocess.DEVNULL,
            ).strip()
            return result
        except (subprocess.CalledProcessError, FileNotFoundError):
            return None

    def get_pane_content(self) -> str | None:
        """Get visible content of current pane."""
        if not self.pane_id:
            return None

        try:
            content = subprocess.check_output(
                ["tmux", "capture-pane", "-t", self.pane_id, "-p"],
                text=True,
                stderr=subprocess.DEVNULL,
            )
            return content
        except (subprocess.CalledProcessError, FileNotFoundError):
            return None
