"""Tahoe-LAFS introducer operations for RedundaNet."""

from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path

from jinja2 import Template

from redundanet.core.exceptions import StorageError
from redundanet.utils.files import ensure_dir, read_file, write_file
from redundanet.utils.logging import get_logger
from redundanet.utils.process import is_command_available, run_command

logger = get_logger(__name__)

TAHOE_INTRODUCER_CFG_TEMPLATE = """# Tahoe-LAFS introducer configuration
# Generated by RedundaNet

[node]
nickname = {{ nickname }}
web.port = tcp:{{ web_port }}:interface=0.0.0.0
tub.port = tcp:{{ tub_port }}
tub.location = {{ tub_location }}

[introducer]
# This node is an introducer
"""


@dataclass
class TahoeIntroducerConfig:
    """Configuration for Tahoe-LAFS introducer."""

    nickname: str
    node_dir: Path
    vpn_ip: str
    web_port: int = 3458
    tub_port: int = 3458

    @property
    def tub_location(self) -> str:
        """Get the tub location for this introducer."""
        return f"tcp:{self.vpn_ip}:{self.tub_port}"


class TahoeIntroducer:
    """Manages Tahoe-LAFS introducer node."""

    def __init__(self, config: TahoeIntroducerConfig) -> None:
        self.config = config
        self._tahoe_cfg = config.node_dir / "tahoe.cfg"
        self._furl_file = config.node_dir / "private" / "introducer.furl"

    def ensure_tahoe_installed(self) -> bool:
        """Check if Tahoe-LAFS is installed."""
        if not is_command_available("tahoe"):
            raise StorageError("Tahoe-LAFS is not installed.")
        return True

    def create_node(self) -> str:
        """Create a new Tahoe-LAFS introducer node.

        Returns:
            The introducer FURL
        """
        logger.info("Creating Tahoe introducer", nickname=self.config.nickname)

        self.ensure_tahoe_installed()
        ensure_dir(self.config.node_dir, mode=0o700)

        # Create the introducer (nickname is set in tahoe.cfg, not command line)
        # Use --listen=none initially, we'll configure the proper settings in tahoe.cfg
        result = run_command(
            f"tahoe create-introducer --listen=none {self.config.node_dir}",
            check=False,
        )

        if not result.success and "already exists" not in result.stderr:
            raise StorageError(f"Failed to create introducer: {result.stderr}")

        # Write custom configuration
        self._write_config()

        # Start the introducer to generate the FURL
        self.start()

        # Wait for FURL to be generated
        import time

        for _ in range(30):
            if self._furl_file.exists():
                break
            time.sleep(1)

        if not self._furl_file.exists():
            raise StorageError("FURL file not generated after starting introducer")

        furl = self.get_furl()
        logger.info("Tahoe introducer created", furl=furl[:50] + "...")

        return furl

    def _write_config(self) -> None:
        """Write tahoe.cfg configuration file."""
        template = Template(TAHOE_INTRODUCER_CFG_TEMPLATE)
        content = template.render(
            nickname=self.config.nickname,
            web_port=self.config.web_port,
            tub_port=self.config.tub_port,
            tub_location=self.config.tub_location,
        )

        write_file(self._tahoe_cfg, content, mode=0o600)
        logger.debug("Wrote tahoe.cfg", path=str(self._tahoe_cfg))

    def start(self) -> bool:
        """Start the Tahoe introducer."""
        logger.info("Starting Tahoe introducer", nickname=self.config.nickname)

        result = run_command(f"tahoe start {self.config.node_dir}", check=False)

        if not result.success:
            logger.error("Failed to start Tahoe introducer", error=result.stderr)
            return False

        logger.info("Tahoe introducer started")
        return True

    def stop(self) -> bool:
        """Stop the Tahoe introducer."""
        logger.info("Stopping Tahoe introducer", nickname=self.config.nickname)

        result = run_command(f"tahoe stop {self.config.node_dir}", check=False)

        if not result.success:
            logger.error("Failed to stop Tahoe introducer", error=result.stderr)
            return False

        logger.info("Tahoe introducer stopped")
        return True

    def restart(self) -> bool:
        """Restart the Tahoe introducer."""
        result = run_command(f"tahoe restart {self.config.node_dir}", check=False)
        return result.success

    def is_running(self) -> bool:
        """Check if the introducer is running."""
        result = run_command(f"tahoe status {self.config.node_dir}", check=False)
        return result.success and "RUNNING" in result.stdout

    def get_furl(self) -> str:
        """Get the introducer FURL.

        Returns:
            The introducer FURL string
        """
        if not self._furl_file.exists():
            raise StorageError(f"FURL file not found: {self._furl_file}")

        return read_file(self._furl_file).strip()

    def get_status(self) -> dict[str, object]:
        """Get introducer status."""
        status: dict[str, object] = {
            "running": self.is_running(),
            "node_dir": str(self.config.node_dir),
            "web_url": f"http://{self.config.vpn_ip}:{self.config.web_port}",
        }

        if self._furl_file.exists():
            status["furl"] = self.get_furl()

        return status
