"""Tahoe-LAFS storage node operations for RedundaNet."""

from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path

from jinja2 import Template

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

logger = get_logger(__name__)

TAHOE_STORAGE_CFG_TEMPLATE = """# Tahoe-LAFS storage node configuration
# Generated by RedundaNet

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

[client]
introducer.furl = {{ introducer_furl }}
shares.needed = {{ shares_needed }}
shares.happy = {{ shares_happy }}
shares.total = {{ shares_total }}

[storage]
enabled = true
reserved_space = {{ reserved_space }}
{% if storage_dir %}storage_dir = {{ storage_dir }}{% endif %}

[helper]
enabled = false
"""


@dataclass
class TahoeStorageConfig:
    """Configuration for Tahoe-LAFS storage node."""

    nickname: str
    node_dir: Path
    introducer_furl: str
    reserved_space: str = "50G"
    storage_dir: Path | None = None
    web_port: int = 3457
    tub_port: int = 34570
    tub_location: str = "AUTO"
    shares_needed: int = 3
    shares_happy: int = 7
    shares_total: int = 10

    @classmethod
    def from_tahoe_config(
        cls,
        nickname: str,
        introducer_furl: str,
        tahoe_config: TahoeConfig,
        node_dir: Path | None = None,
        storage_dir: Path | None = None,
    ) -> TahoeStorageConfig:
        """Create storage config from TahoeConfig."""
        return cls(
            nickname=nickname,
            node_dir=node_dir or Path("/var/lib/tahoe-storage"),
            introducer_furl=introducer_furl,
            reserved_space=tahoe_config.reserved_space,
            storage_dir=storage_dir,
            shares_needed=tahoe_config.shares_needed,
            shares_happy=tahoe_config.shares_happy,
            shares_total=tahoe_config.shares_total,
        )


class TahoeStorage:
    """Manages Tahoe-LAFS storage node."""

    def __init__(self, config: TahoeStorageConfig) -> None:
        self.config = config
        self._tahoe_cfg = config.node_dir / "tahoe.cfg"

    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) -> None:
        """Create a new Tahoe-LAFS storage node."""
        logger.info("Creating Tahoe storage node", nickname=self.config.nickname)

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

        if self.config.storage_dir:
            ensure_dir(self.config.storage_dir, mode=0o700)

        # Create the node
        result = run_command(
            f"tahoe create-node --basedir={self.config.node_dir} "
            f"--nickname={self.config.nickname}",
            check=False,
        )

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

        # Write custom configuration
        self._write_config()

        logger.info("Tahoe storage node created", node_dir=str(self.config.node_dir))

    def _write_config(self) -> None:
        """Write tahoe.cfg configuration file."""
        template = Template(TAHOE_STORAGE_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,
            introducer_furl=self.config.introducer_furl,
            reserved_space=self.config.reserved_space,
            storage_dir=str(self.config.storage_dir) if self.config.storage_dir else None,
            shares_needed=self.config.shares_needed,
            shares_happy=self.config.shares_happy,
            shares_total=self.config.shares_total,
        )

        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 storage node."""
        logger.info("Starting Tahoe storage", 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 storage", error=result.stderr)
            return False

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

    def stop(self) -> bool:
        """Stop the Tahoe storage node."""
        logger.info("Stopping Tahoe storage", 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 storage", error=result.stderr)
            return False

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

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

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

    def get_stats(self) -> dict[str, object]:
        """Get storage statistics."""
        stats: dict[str, object] = {
            "running": self.is_running(),
            "node_dir": str(self.config.node_dir),
            "reserved_space": self.config.reserved_space,
        }

        # Try to get disk usage
        storage_path = self.config.storage_dir or (self.config.node_dir / "storage" / "shares")
        if storage_path.exists():
            result = run_command(f"du -sh {storage_path}", check=False)
            if result.success:
                stats["used_space"] = result.stdout.split()[0]

        return stats

    def update_introducer_furl(self, furl: str) -> None:
        """Update the introducer FURL in the configuration."""
        self.config.introducer_furl = furl
        self._write_config()
        logger.info("Updated introducer FURL")
