"""
Docker Mailserver Service
透過 SSH + docker exec 管理 Docker Mailserver 郵件帳號

部署架構:
  HR Portal (10.1.0.245 或正式環境) --SSH--> Ubuntu Server (10.1.0.254)
  Ubuntu Server --> docker exec mailserver setup ...

整合方式:
  paramiko SSH → docker exec mailserver setup email add/del/quota set

失敗處理原則:
  - SSH 連線失敗以 warning 記錄，回傳包含 error 的結果字典
  - 不拋出例外，不影響 Keycloak 等其他 onboarding 流程
"""
import logging
from typing import Dict, Any, Optional

logger = logging.getLogger(__name__)

# 郵件配額設定 (MB)，依職級對應
MAIL_QUOTA_BY_JOB_LEVEL = {
    "Junior": 2048,    # 2 GB
    "Mid": 3072,       # 3 GB
    "Senior": 5120,    # 5 GB
    "Manager": 10240,  # 10 GB
}


def get_mail_quota_by_job_level(job_level: str) -> int:
    """根據職級取得郵件配額 (MB)"""
    return MAIL_QUOTA_BY_JOB_LEVEL.get(job_level, MAIL_QUOTA_BY_JOB_LEVEL["Junior"])


class MailserverService:
    """
    Docker Mailserver 管理 Service

    透過 SSH 連線到 Ubuntu Server (10.1.0.254)，
    再執行 docker exec mailserver setup 指令管理郵件帳號。

    支援操作:
    - 建立郵件帳號
    - 設定配額
    - 停用帳號 (停止收信，保留資料)
    - 設定轉寄
    - 查詢帳號狀態
    """

    def __init__(self, ssh_host: str, ssh_port: int, ssh_user: str, ssh_password: str,
                 container_name: str = "mailserver", timeout: int = 30):
        self.ssh_host = ssh_host
        self.ssh_port = ssh_port
        self.ssh_user = ssh_user
        self.ssh_password = ssh_password
        self.container_name = container_name
        self.timeout = timeout

    def _exec_docker_command(self, *setup_args) -> tuple[bool, str, str]:
        """
        透過 SSH 執行 docker exec mailserver setup 指令

        Args:
            *setup_args: setup 子指令參數
                例如: "email", "add", "user@domain.com", "password"

        Returns:
            (success: bool, stdout: str, stderr: str)
        """
        try:
            import paramiko
        except ImportError:
            logger.error("缺少 paramiko 套件，請執行: pip install paramiko")
            return False, "", "缺少 paramiko 套件"

        cmd = f"docker exec {self.container_name} setup " + " ".join(
            f'"{arg}"' if " " in str(arg) else str(arg) for arg in setup_args
        )
        logger.debug(f"執行 Mailserver 指令: docker exec {self.container_name} setup {' '.join(str(a) for a in setup_args[:2])} ...")

        ssh = None
        try:
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            ssh.connect(
                hostname=self.ssh_host,
                port=self.ssh_port,
                username=self.ssh_user,
                password=self.ssh_password,
                timeout=self.timeout,
            )

            stdin, stdout, stderr = ssh.exec_command(cmd, timeout=self.timeout)
            out = stdout.read().decode("utf-8", errors="replace").strip()
            err = stderr.read().decode("utf-8", errors="replace").strip()
            rc = stdout.channel.recv_exit_status()

            success = (rc == 0)
            if not success:
                logger.warning(f"Mailserver 指令失敗 (rc={rc}): {err or out}")
            return success, out, err

        except Exception as e:
            logger.warning(f"SSH 連線到 {self.ssh_host} 失敗: {e}")
            return False, "", str(e)
        finally:
            if ssh:
                try:
                    ssh.close()
                except Exception:
                    pass

    def create_email_account(
        self,
        email: str,
        password: str,
        quota_mb: int,
    ) -> Dict[str, Any]:
        """
        建立郵件帳號

        執行:
          docker exec mailserver setup email add <email> <password>
          docker exec mailserver setup quota set <email> <quota>M

        Args:
            email: 郵件地址 (例: user@porscheworld.tw)
            password: 初始密碼 (建議後續透過 Keycloak SSO 管理)
            quota_mb: 配額 (MB)

        Returns:
            {"created": bool, "email": str, "quota_mb": int, "message": str, "error": str|None}
        """
        # 1. 建立帳號
        success, out, err = self._exec_docker_command(
            "email", "add", email, password
        )
        if not success:
            return {
                "created": False,
                "email": email,
                "quota_mb": quota_mb,
                "message": "建立郵件帳號失敗",
                "error": err or out,
            }

        logger.info(f"Mailserver: 郵件帳號建立成功 {email}")

        # 2. 設定配額
        self.set_quota(email, quota_mb)

        return {
            "created": True,
            "email": email,
            "quota_mb": quota_mb,
            "message": f"郵件帳號建立成功 ({quota_mb}MB)",
            "error": None,
        }

    def set_quota(self, email: str, quota_mb: int) -> Dict[str, Any]:
        """
        設定郵件配額

        執行:
          docker exec mailserver setup quota set <email> <quota>M

        Returns:
            {"updated": bool, "email": str, "quota_mb": int, "error": str|None}
        """
        success, out, err = self._exec_docker_command(
            "quota", "set", email, f"{quota_mb}M"
        )
        if success:
            logger.info(f"Mailserver: 配額設定成功 {email} → {quota_mb}MB")
        else:
            logger.warning(f"Mailserver: 配額設定失敗 {email}: {err}")

        return {
            "updated": success,
            "email": email,
            "quota_mb": quota_mb,
            "error": None if success else (err or out),
        }

    def delete_email_account(self, email: str) -> Dict[str, Any]:
        """
        刪除郵件帳號

        執行:
          docker exec mailserver setup email del <email>

        Returns:
            {"deleted": bool, "email": str, "error": str|None}
        """
        success, out, err = self._exec_docker_command(
            "email", "del", email
        )
        if success:
            logger.info(f"Mailserver: 郵件帳號刪除成功 {email}")
        else:
            logger.warning(f"Mailserver: 郵件帳號刪除失敗 {email}: {err}")

        return {
            "deleted": success,
            "email": email,
            "error": None if success else (err or out),
        }

    def list_accounts(self) -> Dict[str, Any]:
        """
        列出所有郵件帳號

        執行:
          docker exec mailserver setup email list

        Returns:
            {"accounts": list[str], "error": str|None}
        """
        success, out, err = self._exec_docker_command("email", "list")
        if success:
            accounts = [line.strip() for line in out.splitlines() if line.strip()]
            return {"accounts": accounts, "error": None}
        return {"accounts": [], "error": err or out}


# ============================================================
# 延遲初始化單例
# ============================================================
_mailserver_service: Optional[MailserverService] = None


def get_mailserver_service() -> MailserverService:
    """取得 MailserverService 單例 (延遲初始化)"""
    global _mailserver_service
    if _mailserver_service is None:
        from app.core.config import settings
        _mailserver_service = MailserverService(
            ssh_host=settings.MAILSERVER_SSH_HOST,
            ssh_port=settings.MAILSERVER_SSH_PORT,
            ssh_user=settings.MAILSERVER_SSH_USER,
            ssh_password=settings.MAILSERVER_SSH_PASSWORD,
            container_name=settings.MAILSERVER_CONTAINER_NAME,
            timeout=settings.MAILSERVER_SSH_TIMEOUT,
        )
    return _mailserver_service
