"""HOME/plugins 管理工具（plugin_list / reload / 备份恢复等）。"""

from __future__ import annotations

from datetime import datetime, timezone
from typing import Any

from aicd.plugins.backup import (
    backup_plugin_directory,
    list_plugin_backups,
    restore_plugin_directory,
)
from aicd.plugins.manifest import PluginManifest, load_manifest_file
from aicd.plugins.plugin_log import (
    list_plugin_log_files,
    read_plugin_log_tail,
)


def _manifest_public(m: PluginManifest) -> dict[str, Any]:
    return {
        "id": m.id,
        "name": m.name,
        "display_name": m.display_name or m.name,
        "version": m.version,
        "enabled": m.enabled,
        "description": m.description,
        "min_aicd_version": m.min_aicd_version,
        "schema_version": m.schema_version,
        "entries": dict(m.entries),
        "config": m.config,
    }


def plugin_list(router: Any, args: dict[str, Any]) -> dict[str, Any]:
    _ = args
    reg = router.plugin_registry
    if not reg:
        return {"ok": False, "error": "plugin registry not available"}
    return {
        "ok": True,
        "plugins": reg.summarize(),
        "load_report_path": str(reg.state_dir / "load_report.json"),
    }


def plugin_info(router: Any, args: dict[str, Any]) -> dict[str, Any]:
    pid = str(args.get("plugin_id") or "").strip()
    if not pid:
        return {"ok": False, "error": "plugin_id required"}
    reg = router.plugin_registry
    if not reg:
        return {"ok": False, "error": "plugin registry not available"}
    root = reg.plugins_root / pid
    manifest_disk: dict[str, Any] | None = None
    yaml_err: str | None = None
    mf_path = root / "plugin.yaml"
    if mf_path.is_file():
        try:
            manifest_disk = _manifest_public(load_manifest_file(mf_path))
        except Exception as e:  # noqa: BLE001
            yaml_err = repr(e)
    summary_row: dict[str, Any] | None = None
    for row in reg.summarize():
        if row.get("id") == pid:
            summary_row = row
            break
    if summary_row is None and manifest_disk is None and not root.is_dir():
        return {"ok": False, "error": f"unknown plugin: {pid}"}
    log_files = list_plugin_log_files(root)
    out: dict[str, Any] = {
        "ok": True,
        "plugin_id": pid,
        "plugin_root": str(root.resolve()),
        "manifest_from_disk": manifest_disk,
        "yaml_parse_error": yaml_err,
        "last_load_summary": summary_row,
        "log_files": log_files,
        "log_hint": "Errors append to logs/YYYY-MM-DD.log (UTC date). Use plugin_read_log.",
    }
    return out


def plugin_read_log(router: Any, args: dict[str, Any]) -> dict[str, Any]:
    pid = str(args.get("plugin_id") or "").strip()
    if not pid:
        return {"ok": False, "error": "plugin_id required"}
    day = args.get("day")
    day_s = str(day).strip() if day not in (None, "") else None
    max_lines = args.get("max_lines")
    mi = 200
    if max_lines is not None:
        try:
            mi = int(max_lines)
        except (TypeError, ValueError):
            pass
    mi = max(1, min(2000, mi))
    reg = router.plugin_registry
    if not reg:
        return {"ok": False, "error": "plugin registry not available"}
    root = reg.plugins_root / pid
    if not root.is_dir():
        return {"ok": False, "error": f"plugin directory not found: {root}"}
    resolved_day = day_s or datetime.now(timezone.utc).date().isoformat()
    ok, text = read_plugin_log_tail(root, day=day_s, max_lines=mi)
    if not ok:
        return {"ok": False, "error": text}
    return {
        "ok": True,
        "plugin_id": pid,
        "day": resolved_day,
        "content": text,
        "log_files": list_plugin_log_files(root),
    }


def plugin_validate(router: Any, args: dict[str, Any]) -> dict[str, Any]:
    _ = args
    return plugin_reload(router, {})


def plugin_load(router: Any, args: dict[str, Any]) -> dict[str, Any]:
    reg = router.plugin_registry
    if not reg:
        return {"ok": False, "error": "plugin registry not available"}
    scope = str(args.get("scope") or "all").strip().lower()
    if scope == "all":
        reg.load_all()
    elif scope == "listed":
        raw = args.get("plugin_ids")
        if not isinstance(raw, list):
            return {"ok": False, "error": "plugin_ids must be a list when scope=listed"}
        ids = frozenset(str(x).strip() for x in raw if str(x).strip())
        if not ids:
            return {"ok": False, "error": "plugin_ids empty"}
        reg.load_all(plugin_ids=ids)
    else:
        return {"ok": False, "error": "scope must be 'all' or 'listed'"}
    router.after_plugin_registry_changed()
    return {"ok": True, "plugins": reg.summarize()}


def plugin_reload(router: Any, args: dict[str, Any]) -> dict[str, Any]:
    _ = args
    reg = router.plugin_registry
    if not reg:
        return {"ok": False, "error": "plugin registry not available"}
    reg.reload()
    router.after_plugin_registry_changed()
    return {"ok": True, "plugins": reg.summarize()}


def plugin_set_enabled(router: Any, args: dict[str, Any]) -> dict[str, Any]:
    pid = str(args.get("plugin_id") or "").strip()
    if not pid:
        return {"ok": False, "error": "plugin_id required"}
    if "enabled" not in args:
        return {"ok": False, "error": "enabled required"}
    en = bool(args.get("enabled"))
    reg = router.plugin_registry
    if not reg:
        return {"ok": False, "error": "plugin registry not available"}
    ok, msg = reg.set_enabled(pid, en)
    router.after_plugin_registry_changed()
    return {"ok": ok, "message": msg}


def plugin_backup_now(router: Any, args: dict[str, Any]) -> dict[str, Any]:
    pid = str(args.get("plugin_id") or "").strip()
    if not pid:
        return {"ok": False, "error": "plugin_id required"}
    reg = router.plugin_registry
    if not reg:
        return {"ok": False, "error": "plugin registry not available"}
    root = reg.plugins_root / pid
    if not root.is_dir():
        return {"ok": False, "error": f"plugin directory not found: {root}"}
    try:
        arc = backup_plugin_directory(
            root,
            reg.backups_dir,
            keep=reg.app.plugins.backup_keep,
        )
    except OSError as e:
        return {"ok": False, "error": str(e)}
    return {"ok": True, "archive": str(arc)}


def plugin_list_backups(router: Any, args: dict[str, Any]) -> dict[str, Any]:
    pid = str(args.get("plugin_id") or "").strip()
    if not pid:
        return {"ok": False, "error": "plugin_id required"}
    reg = router.plugin_registry
    if not reg:
        return {"ok": False, "error": "plugin registry not available"}
    names = list_plugin_backups(reg.backups_dir, pid)
    return {"ok": True, "backups": names}


def plugin_restore_backup(router: Any, args: dict[str, Any]) -> dict[str, Any]:
    pid = str(args.get("plugin_id") or "").strip()
    an = str(args.get("archive_name") or "").strip()
    if not pid or not an:
        return {"ok": False, "error": "plugin_id and archive_name required"}
    reg = router.plugin_registry
    if not reg:
        return {"ok": False, "error": "plugin registry not available"}
    ok, msg = restore_plugin_directory(
        pid,
        an,
        reg.plugins_root,
        reg.backups_dir,
        backup_current_first=True,
        keep=reg.app.plugins.backup_keep,
    )
    if ok:
        reg.reload()
        router.after_plugin_registry_changed()
    return {"ok": ok, "message": msg}


HANDLERS = {
    "plugin_list": plugin_list,
    "plugin_info": plugin_info,
    "plugin_read_log": plugin_read_log,
    "plugin_validate": plugin_validate,
    "plugin_load": plugin_load,
    "plugin_reload": plugin_reload,
    "plugin_set_enabled": plugin_set_enabled,
    "plugin_backup_now": plugin_backup_now,
    "plugin_list_backups": plugin_list_backups,
    "plugin_restore_backup": plugin_restore_backup,
}
