"""Post-upload permission fixup for file manager (reuse rsync push defaults)."""

from __future__ import annotations

import logging
import re
import shlex
from typing import TYPE_CHECKING

from server.application.services.sync_engine_v2 import _RSYNC_CHMOD_RE, _RSYNC_CHOWN_RE

if TYPE_CHECKING:
    from server.domain.models import Server

logger = logging.getLogger(__name__)


def parse_upload_file_mode(chmod_setting: str) -> str | None:
    """Extract octal file mode from rsync-style ``D755,F755`` or plain ``644``."""
    raw = (chmod_setting or "").strip()
    if not raw or not _RSYNC_CHMOD_RE.fullmatch(raw):
        return None
    m = re.search(r"F([0-7]{3,4})", raw, re.IGNORECASE)
    if m:
        return m.group(1)
    if re.fullmatch(r"[0-7]{3,4}", raw):
        return raw
    for part in reversed(raw.split(",")):
        piece = part.strip()
        if len(piece) > 1 and piece[0] in "Ff" and re.fullmatch(r"[0-7]{3,4}", piece[1:]):
            return piece[1:]
    return None


def parse_upload_chown(chown_setting: str) -> tuple[str, str] | None:
    """Return ``(owner, group)`` when setting is valid; else None."""
    raw = (chown_setting or "").strip()
    if not raw or not _RSYNC_CHOWN_RE.fullmatch(raw):
        return None
    if ":" in raw:
        owner, group = raw.split(":", 1)
        return owner.strip(), group.strip()
    return raw, raw


def upload_permission_plan() -> tuple[tuple[str, str] | None, str | None]:
    """Read ``NEXUS_RSYNC_PUSH_CHOWN`` / ``NEXUS_RSYNC_PUSH_CHMOD`` for uploads."""
    from server.config import settings

    return (
        parse_upload_chown(settings.RSYNC_PUSH_CHOWN or ""),
        parse_upload_file_mode(settings.RSYNC_PUSH_CHMOD or ""),
    )


async def apply_upload_file_permissions(server: Server, remote_path: str) -> dict:
    """chown/chmod uploaded file; mirrors rsync push defaults (www:www, F755)."""
    from server.infrastructure.ssh.remote_shell import exec_ssh_command_with_fallback

    chown_pair, file_mode = upload_permission_plan()
    if not chown_pair and not file_mode:
        return {"applied": False, "skipped": True}

    path_q = shlex.quote(remote_path)
    elevated = False
    errors: list[str] = []

    if chown_pair:
        owner_spec = shlex.quote(f"{chown_pair[0]}:{chown_pair[1]}")
        result = await exec_ssh_command_with_fallback(
            server, f"chown {owner_spec} {path_q}", timeout=30,
        )
        elevated = bool(result.get("elevated"))
        if result.get("exit_code") != 0:
            err = ((result.get("stderr") or "") + (result.get("stdout") or "")).strip()[:200]
            errors.append(err or "chown 失败")

    if file_mode and not errors:
        result = await exec_ssh_command_with_fallback(
            server, f"chmod {file_mode} {path_q}", timeout=30,
        )
        elevated = elevated or bool(result.get("elevated"))
        if result.get("exit_code") != 0:
            err = ((result.get("stderr") or "") + (result.get("stdout") or "")).strip()[:200]
            errors.append(err or "chmod 失败")

    if errors:
        logger.warning(
            "Upload permission fixup failed for %s on server %s: %s",
            remote_path,
            getattr(server, "id", "?"),
            "; ".join(errors),
        )

    owner, group = chown_pair if chown_pair else (None, None)
    return {
        "applied": not errors and bool(chown_pair or file_mode),
        "skipped": False,
        "owner": owner,
        "group": group,
        "mode": file_mode,
        "elevated": elevated,
        "error": "; ".join(errors) if errors else None,
    }
