"""
organization/manager.py - 组织管理器
====================================
管理组织信息、组织知识库，提供文件的增删查功能。

目录结构:
  ~/.myagent/data/organization/
    ├── organization.md          # 组织信息模板
    └── knowledge/               # 组织知识库
        ├── knowledge_index.json  # 文件元数据索引
        └── *.md, *.txt, ...     # 知识文件
"""
from __future__ import annotations

import json
import shutil
from pathlib import Path
from typing import Any, Dict, List, Optional

from core.logger import get_logger
from core.utils import timestamp

logger = get_logger("myagent.organization")

# 支持上传的文件扩展名
SUPPORTED_EXTENSIONS = {".md", ".txt", ".json", ".csv", ".py", ".js", ".html"}

# 组织信息模板
ORG_INFO_TEMPLATE = """# 组织信息

## 组织名称
<!-- 在此填写组织名称 -->

## 组织简介
<!-- 在此填写组织简介 -->

## 业务领域
<!-- 在此填写业务领域 -->

## 核心价值观
<!-- 在此填写核心价值观 -->

## 团队成员
<!-- 在此填写团队成员信息 -->

## 注意事项
<!-- 在此填写其他注意事项 -->
"""


class OrganizationManager:
    """
    组织管理器。

    使用示例:
        om = OrganizationManager(data_dir="~/.myagent/data")
        om.initialize()

        # 读取组织信息
        info = om.get_org_info()

        # 更新组织信息
        om.update_org_info("# 我的公司\n## 简介\n...")

        # 知识库操作
        om.upload_file("policy.md", content)
        files = om.list_knowledge_files()
        om.delete_file("policy.md")
    """

    def __init__(self, data_dir: str | Path = ""):
        self.data_dir = Path(data_dir) if data_dir else Path()
        self._org_dir: Optional[Path] = None
        self._knowledge_dir: Optional[Path] = None
        self._org_info_path: Optional[Path] = None
        self._index_path: Optional[Path] = None

    def initialize(self):
        """初始化目录结构"""
        self._org_dir = self.data_dir / "organization"
        self._knowledge_dir = self._org_dir / "knowledge"
        self._org_info_path = self._org_dir / "organization.md"
        self._index_path = self._knowledge_dir / "knowledge_index.json"

        # 创建目录
        self._org_dir.mkdir(parents=True, exist_ok=True)
        self._knowledge_dir.mkdir(parents=True, exist_ok=True)

        # 创建组织信息模板（仅当不存在时）
        if not self._org_info_path.exists():
            self._org_info_path.write_text(
                ORG_INFO_TEMPLATE, encoding="utf-8"
            )
            logger.info("已创建组织信息模板")

        # 创建知识库索引（仅当不存在时）
        if not self._index_path.exists():
            self._save_index({})
            logger.info("已创建知识库索引")

        logger.info(f"组织管理器已初始化 (dir={self._org_dir})")

    # ==========================================================================
    # 组织信息
    # ==========================================================================

    def get_org_info(self) -> str:
        """读取组织信息 (organization.md 内容)"""
        if not self._org_info_path or not self._org_info_path.exists():
            return ORG_INFO_TEMPLATE
        try:
            return self._org_info_path.read_text(encoding="utf-8")
        except Exception as e:
            logger.error(f"读取组织信息失败: {e}")
            return ""

    def update_org_info(self, content: str) -> bool:
        """更新组织信息"""
        if not self._org_info_path:
            return False
        try:
            self._org_info_path.write_text(content, encoding="utf-8")
            logger.info("组织信息已更新")
            return True
        except Exception as e:
            logger.error(f"更新组织信息失败: {e}")
            return False

    # ==========================================================================
    # 知识库索引
    # ==========================================================================

    def _load_index(self) -> Dict[str, Any]:
        """加载知识库索引"""
        if not self._index_path or not self._index_path.exists():
            return {}
        try:
            return json.loads(
                self._index_path.read_text(encoding="utf-8")
            )
        except (json.JSONDecodeError, IOError) as e:
            logger.warning(f"加载知识库索引失败: {e}")
            return {}

    def _save_index(self, index: Dict[str, Any]):
        """保存知识库索引"""
        if not self._index_path:
            return
        try:
            self._index_path.write_text(
                json.dumps(index, ensure_ascii=False, indent=2),
                encoding="utf-8",
            )
        except Exception as e:
            logger.error(f"保存知识库索引失败: {e}")

    # ==========================================================================
    # 知识库文件管理
    # ==========================================================================

    def list_knowledge_files(self) -> List[Dict[str, Any]]:
        """
        列出知识库中的所有文件和文件夹（递归列出子目录文件）。

        Returns:
            文件列表 [{name, path, type, size, updated_at}]
        """
        if not self._knowledge_dir or not self._knowledge_dir.exists():
            return []

        index = self._load_index()
        files = []

        for item in sorted(self._knowledge_dir.iterdir()):
            # 跳过索引文件
            if item.name == "knowledge_index.json":
                continue

            if item.is_file():
                rel_path = item.name
                file_idx = index.get(rel_path, {})
                stat = item.stat()
                files.append({
                    "name": item.name,
                    "path": rel_path,
                    "type": "file",
                    "size": stat.st_size,
                    "updated_at": file_idx.get("updated_at", timestamp()),
                    "uploaded_by": file_idx.get("uploaded_by", ""),
                })
            elif item.is_dir():
                # 递归列出子目录中的文件
                sub_files = [
                    f for f in item.rglob("*")
                    if f.is_file() and f.suffix.lower() in SUPPORTED_EXTENSIONS
                ]
                # 添加子目录自身
                files.append({
                    "name": item.name,
                    "path": item.name,
                    "type": "dir",
                    "size": 0,
                    "file_count": len(sub_files),
                })
                # 递归添加子目录中的文件（带相对路径）
                for f in sub_files:
                    rel_path = str(f.relative_to(self._knowledge_dir))
                    file_idx = index.get(rel_path, {})
                    try:
                        stat = f.stat()
                        files.append({
                            "name": f.name,
                            "path": rel_path,
                            "type": "file",
                            "size": stat.st_size,
                            "updated_at": file_idx.get("updated_at", timestamp()),
                            "uploaded_by": file_idx.get("uploaded_by", ""),
                        })
                    except OSError:
                        pass

        return files

    def upload_file(
        self,
        filename: str,
        content: str,
        uploaded_by: str = "",
    ) -> Dict[str, Any]:
        """
        上传文件到知识库。

        Args:
            filename: 文件名（支持子目录，如 "policies/leave.md"）
            content: 文件内容
            uploaded_by: 上传者标识（agent path）

        Returns:
            {ok, path, message}
        """
        if not self._knowledge_dir:
            return {"ok": False, "message": "知识库未初始化"}

        # 安全校验: 不允许路径遍历
        safe_name = Path(filename).name
        if ".." in filename or filename.startswith("/"):
            return {"ok": False, "message": "非法文件名"}

        # 检查扩展名
        ext = Path(safe_name).suffix.lower()
        if ext and ext not in SUPPORTED_EXTENSIONS:
            return {"ok": False, "message": f"不支持的文件类型: {ext}"}

        # 处理子目录
        if "/" in filename:
            parts = filename.split("/")
            parent_dir = self._knowledge_dir / "/".join(parts[:-1])
            parent_dir.mkdir(parents=True, exist_ok=True)
            file_name = parts[-1]
            file_path = parent_dir / file_name
        else:
            file_name = safe_name
            file_path = self._knowledge_dir / safe_name

        # 写入文件
        try:
            file_path.write_text(content, encoding="utf-8")
        except Exception as e:
            return {"ok": False, "message": f"写入文件失败: {e}"}

        # 更新索引
        rel_path = str(file_path.relative_to(self._knowledge_dir))
        index = self._load_index()
        index[rel_path] = {
            "filename": file_name,
            "size": len(content),
            "updated_at": timestamp(),
            "uploaded_by": uploaded_by,
        }
        self._save_index(index)

        logger.info(f"知识库文件已上传: {rel_path} (by={uploaded_by})")
        return {"ok": True, "path": rel_path, "message": "上传成功"}

    def delete_file(self, file_path: str) -> Dict[str, Any]:
        """
        删除知识库中的文件或文件夹。

        Args:
            file_path: 相对路径（如 "policies/leave.md" 或 "policies"）

        Returns:
            {ok, message, deleted_count}
        """
        if not self._knowledge_dir:
            return {"ok": False, "message": "知识库未初始化"}

        # 安全校验
        if ".." in file_path or file_path.startswith("/"):
            return {"ok": False, "message": "非法路径"}

        target = self._knowledge_dir / file_path

        if not target.exists():
            return {"ok": False, "message": f"文件不存在: {file_path}"}

        # 不允许删除索引文件
        if target == self._index_path:
            return {"ok": False, "message": "不允许删除索引文件"}

        try:
            deleted_count = 0
            if target.is_dir():
                # 递归删除目录
                for f in target.rglob("*"):
                    if f.is_file():
                        rel = str(f.relative_to(self._knowledge_dir))
                        deleted_count += 1
                shutil.rmtree(target)
            else:
                deleted_count = 1
                target.unlink()

            # 更新索引: 移除已删除文件的记录
            index = self._load_index()
            to_remove = [
                k for k in index
                if k == file_path or k.startswith(file_path + "/")
            ]
            for k in to_remove:
                del index[k]
            self._save_index(index)

            logger.info(f"知识库文件已删除: {file_path} ({deleted_count} 个文件)")
            return {
                "ok": True,
                "message": f"已删除 {deleted_count} 个文件",
                "deleted_count": deleted_count,
            }
        except Exception as e:
            return {"ok": False, "message": f"删除失败: {e}"}

    def read_knowledge_file(self, file_path: str) -> Optional[str]:
        """
        读取知识库文件内容。

        Args:
            file_path: 相对路径

        Returns:
            文件内容，不存在则返回 None
        """
        if not self._knowledge_dir:
            return None

        if ".." in file_path or file_path.startswith("/"):
            return None

        target = self._knowledge_dir / file_path
        if not target.exists() or not target.is_file():
            return None

        try:
            return target.read_text(encoding="utf-8", errors="replace")
        except Exception:
            return None
