"""包管理插件 - 提供插件配置管理和商店界面"""
import os
import sys
import json
import urllib.request
from pathlib import Path
from oss.logger.logger import Log
from oss.plugin.types import Plugin, Response, register_plugin_type


# Gitee 仓库配置
GITEE_OWNER = "starlight-apk"
GITEE_REPO = "future-oss"
GITEE_BRANCH = "main"
# 使用 raw 文件 URL（不走 API，无频率限制）
GITEE_RAW_BASE = f"https://gitee.com/{GITEE_OWNER}/{GITEE_REPO}/raw/{GITEE_BRANCH}"
GITEE_API_BASE = f"https://gitee.com/api/v5/repos/{GITEE_OWNER}/{GITEE_REPO}/contents"
# Gitee Token（从环境变量读取，可选）
GITEE_TOKEN = os.environ.get("GITEE_TOKEN", "")


def _gitee_request(url: str, timeout: int = 15):
    """Gitee 请求"""
    req = urllib.request.Request(url)
    req.add_header("User-Agent", "FutureOSS-PkgManager")
    if GITEE_TOKEN:
        # Gitee 使用私人令牌认证
        req.add_header("Authorization", f"token {GITEE_TOKEN}")
    return urllib.request.urlopen(req, timeout=timeout)


class PkgManagerPlugin(Plugin):
    """包管理插件"""

    def __init__(self):
        self.webui = None
        self.storage = None
        self.store_dir = Path("./store")
        self._remote_cache = None
        self._cache_time = 0
        self._cache_ttl = 300  # 5分钟缓存

    def meta(self):
        from oss.plugin.types import Metadata, PluginConfig, Manifest
        return Manifest(
            metadata=Metadata(
                name="pkg-manager",
                version="1.0.0",
                author="FutureOSS",
                description="插件包管理器 - 配置管理和商店"
            ),
            config=PluginConfig(enabled=True, args={}),
            dependencies=["http-api", "webui", "plugin-storage"]
        )

    def set_webui(self, webui):
        self.webui = webui

    def set_plugin_storage(self, storage):
        self.storage = storage

    def init(self, deps: dict = None):
        """init 阶段：注册页面到 WebUI"""
        if not self.webui:
            Log.warn("pkg-manager", "警告: 未找到 WebUI 依赖")
            return

        self.webui.register_page(
            path='/packages',
            content_provider=self._packages_content,
            nav_item={'icon': 'ri-apps-line', 'text': '插件管理'}
        )
        self.webui.register_page(
            path='/store',
            content_provider=self._store_content,
            nav_item={'icon': 'ri-store-2-line', 'text': '插件商店'}
        )
        Log.info("pkg-manager", "已注册到 WebUI 导航")

    def start(self):
        """启动阶段：注册 API 路由"""
        if not self.webui or not hasattr(self.webui, 'server') or not self.webui.server:
            Log.warn("pkg-manager", "警告: WebUI 服务器未就绪")
            return

        router = self.webui.server.router

        # API - 已安装插件
        router.get("/api/plugins", self._handle_list_plugins)
        router.get("/api/plugins/:name/config", self._handle_get_config)
        router.post("/api/plugins/:name/config", self._handle_save_config)
        router.get("/api/plugins/:name/info", self._handle_get_plugin_info)
        router.post("/api/plugins/:name/uninstall", self._handle_uninstall)

        # API - 远程商店
        router.get("/api/store/remote", self._handle_remote_store)
        router.post("/api/store/install", self._handle_store_install)

        Log.info("pkg-manager", "包管理器已启动")

    def stop(self):
        Log.error("pkg-manager", "包管理器已停止")

    # ==================== 页面渲染 ====================

    def _packages_content(self) -> str:
        return self._render_php_view('packages.php', {'pageTitle': '插件管理'})

    def _store_content(self) -> str:
        return self._render_php_view('store.php', {'pageTitle': '插件商店'})

    def _render_php_view(self, view_name: str, variables: dict) -> str:
        import subprocess

        views_dir = os.path.join(os.path.dirname(__file__), 'views')
        php_file = os.path.join(views_dir, view_name)
        if not os.path.exists(php_file):
            return f"<h1>错误: 找不到 {view_name}</h1>"

        php_vars = ""
        for key, value in variables.items():
            if isinstance(value, str):
                php_vars += f"${key} = '{value}';\n"
            else:
                php_vars += f"${key} = {json.dumps(value)};\n"

        with open(php_file, 'r', encoding='utf-8') as f:
            php_content = f.read()

        tmp_file = os.path.join(views_dir, '.temp_pkg.php')
        try:
            with open(tmp_file, 'w', encoding='utf-8') as f:
                f.write(f"<?php\n{php_vars}\n?>\n{php_content}")

            result = subprocess.run(
                ["php", "-f", tmp_file],
                capture_output=True, text=True, timeout=10, cwd=views_dir,
                encoding='utf-8', errors='replace'
            )
            return result.stdout if result.returncode == 0 else f"<pre>{result.stderr}</pre>"
        finally:
            try:
                if os.path.exists(tmp_file):
                    os.unlink(tmp_file)
            except:
                pass

    # ==================== API 处理 ====================

    def _handle_list_plugins(self, request):
        """列出所有已安装插件"""
        plugins = self._scan_all_plugins()
        return Response(status=200, headers={"Content-Type": "application/json"}, body=json.dumps(plugins, ensure_ascii=False))

    def _handle_get_config(self, request):
        """获取插件配置 schema + 当前值"""
        plugin_name = request.path_params.get('name', '')
        schema = self._load_config_schema(plugin_name)
        current = self._load_plugin_config(plugin_name)
        return Response(status=200, headers={"Content-Type": "application/json"}, body=json.dumps({
            "schema": schema,
            "current": current
        }, ensure_ascii=False))

    def _handle_save_config(self, request):
        """保存插件配置"""
        import json as json_mod
        try:
            body = json_mod.loads(request.body)
            plugin_name = request.path_params.get('name', '')
            self._save_plugin_config(plugin_name, body)
            return Response(status=200, headers={"Content-Type": "application/json"}, body='{"ok":true}')
        except Exception as e:
            return Response(status=500, headers={"Content-Type": "application/json"}, body=json.dumps({"error": str(e)}))

    def _handle_get_plugin_info(self, request):
        """获取插件详细信息"""
        plugin_name = request.path_params.get('name', '')
        info = self._get_plugin_detailed_info(plugin_name)
        return Response(status=200, headers={"Content-Type": "application/json"}, body=json.dumps(info, ensure_ascii=False))

    def _handle_uninstall(self, request):
        """卸载插件"""
        import shutil
        plugin_name = request.path_params.get('name', '')
        # 查找插件目录
        plugin_dir = self._find_plugin_dir(plugin_name)
        if not plugin_dir:
            return Response(status=404, body='{"error":"插件未安装"}')
        try:
            shutil.rmtree(plugin_dir)
            return Response(status=200, body='{"ok":true}')
        except Exception as e:
            return Response(status=500, body=json.dumps({"error": str(e)}))

    def _handle_remote_store(self, request):
        """从 Gitee API 获取远程插件列表"""
        try:
            plugins = self._fetch_remote_plugins()
            return Response(status=200, headers={"Content-Type": "application/json"}, body=json.dumps(plugins, ensure_ascii=False))
        except Exception as e:
            return Response(status=500, body=json.dumps({"error": str(e)}))

    def _handle_store_install(self, request):
        """安装插件"""
        import json as json_mod
        try:
            body = json_mod.loads(request.body)
            name = body.get("name", "")
            author = body.get("author", "FutureOSS")
            success = self._install_from_gitee(name, author)
            return Response(status=200, body=json.dumps({"ok": success}))
        except Exception as e:
            return Response(status=500, body=json.dumps({"error": str(e)}))

    # ==================== Gitee 远程商店 ====================

    def _fetch_remote_plugins(self) -> list:
        """从 Gitee 获取所有可用插件（带缓存+限速+重试）"""
        import time
        now = time.time()
        if self._remote_cache and (now - self._cache_time) < self._cache_ttl:
            return self._remote_cache

        plugins = []
        try:
            store_url = f"{GITEE_API_BASE}/store"
            # 重试 3 次，每次间隔增加
            for attempt in range(3):
                try:
                    with _gitee_request(store_url, timeout=15) as resp:
                        dirs = json.loads(resp.read().decode("utf-8"))
                    break
                except Exception as e:
                    if attempt < 2:
                        time.sleep(1 + attempt)
                        continue
                    raise

            time.sleep(0.5)

            for dir_info in dirs:
                if dir_info.get("type") != "dir":
                    continue
                author = dir_info.get("name", "")
                if not author.startswith("@{"):
                    continue

                author_url = f"{GITEE_API_BASE}/store/{urllib.parse.quote(author, safe='')}"
                for attempt in range(3):
                    try:
                        with _gitee_request(author_url, timeout=15) as resp:
                            plugin_dirs = json.loads(resp.read().decode("utf-8"))
                        break
                    except Exception:
                        if attempt < 2:
                            time.sleep(1 + attempt)
                            continue
                        raise

                time.sleep(0.5)

                for plugin_dir in plugin_dirs:
                    if plugin_dir.get("type") != "dir":
                        continue
                    plugin_name = plugin_dir.get("name", "")

                    manifest_url = f"{GITEE_API_BASE}/store/{urllib.parse.quote(author, safe='')}/{plugin_name}/manifest.json"
                    manifest = {}
                    for attempt in range(3):
                        try:
                            with _gitee_request(manifest_url, timeout=15) as resp:
                                manifest = json.loads(resp.read().decode("utf-8"))
                            break
                        except Exception:
                            if attempt < 2:
                                time.sleep(1 + attempt)
                                continue

                    plugins.append({
                        "name": plugin_name,
                        "author": author,
                        "full_name": f"{author}/{plugin_name}",
                        "metadata": manifest.get("metadata", {}),
                        "dependencies": manifest.get("dependencies", []),
                        "has_config": False,
                        "is_installed": self._is_plugin_installed(plugin_name, author)
                    })

                time.sleep(0.5)

            self._remote_cache = plugins
            self._cache_time = now
        except Exception as e:
            Log.error("pkg-manager", f"获取远程插件列表失败: {e}")

        return plugins

    def _install_from_gitee(self, plugin_name: str, author: str) -> bool:
        """从 Gitee 下载并安装插件（使用 raw URL）"""
        import shutil, time
        install_dir = self.store_dir / author / plugin_name
        install_dir.mkdir(parents=True, exist_ok=True)

        try:
            # 获取目录结构（需要一次 API 调用）
            api_url = f"{GITEE_API_BASE}/store/{author}/{plugin_name}"
            with _gitee_request(api_url, timeout=15) as resp:
                items = json.loads(resp.read().decode("utf-8"))

            time.sleep(0.5)

            for item in items:
                if item.get("type") == "file":
                    # 使用 raw URL 下载文件（不走 API）
                    filename = item.get("name")
                    raw_url = f"{GITEE_RAW_BASE}/store/{author}/{plugin_name}/{filename}"
                    local_file = install_dir / filename
                    try:
                        with _gitee_request(raw_url, timeout=15) as resp:
                            content = resp.read()
                        with open(local_file, 'wb') as f:
                            f.write(content)
                    except:
                        pass
                elif item.get("type") == "dir":
                    sub_dir = item.get("name")
                    self._download_dir_raw(author, plugin_name, sub_dir, install_dir / sub_dir)
                    time.sleep(0.3)

            Log.info("pkg-manager", f"已安装: {author}/{plugin_name}")
            return True
        except Exception as e:
            Log.error("pkg-manager", f"安装失败 {plugin_name}: {e}")
            if install_dir.exists():
                shutil.rmtree(install_dir)
            return False

    def _download_dir_raw(self, author: str, plugin: str, sub_dir: str, local_dir: Path):
        """使用 raw URL 递归下载子目录"""
        import time
        try:
            api_url = f"{GITEE_API_BASE}/store/{author}/{plugin}/{sub_dir}"
            with _gitee_request(api_url, timeout=15) as resp:
                items = json.loads(resp.read().decode("utf-8"))

            local_dir.mkdir(parents=True, exist_ok=True)
            for item in items:
                if item.get("type") == "file":
                    filename = item.get("name")
                    raw_url = f"{GITEE_RAW_BASE}/store/{author}/{plugin}/{sub_dir}/{filename}"
                    try:
                        with _gitee_request(raw_url, timeout=15) as resp:
                            content = resp.read()
                        with open(local_dir / filename, 'wb') as f:
                            f.write(content)
                    except:
                        pass
                elif item.get("type") == "dir":
                    self._download_dir_raw(author, plugin, f"{sub_dir}/{item.get('name')}", local_dir / item.get("name"))
        except:
            pass

    # ==================== 辅助方法 ====================

    def _scan_all_plugins(self) -> list:
        """扫描本地已安装插件"""
        plugins = []
        if not self.store_dir.exists():
            return plugins

        for author_dir in self.store_dir.iterdir():
            if author_dir.is_dir() and author_dir.name.startswith("@{"):
                for plugin_dir in author_dir.iterdir():
                    if plugin_dir.is_dir() and (plugin_dir / "main.py").exists():
                        manifest_path = plugin_dir / "manifest.json"
                        if manifest_path.exists():
                            with open(manifest_path, 'r', encoding='utf-8') as f:
                                manifest = json.load(f)
                            plugins.append({
                                "name": plugin_dir.name,
                                "full_name": f"{author_dir.name}/{plugin_dir.name}",
                                "author": author_dir.name,
                                "metadata": manifest.get("metadata", {}),
                                "dependencies": manifest.get("dependencies", []),
                                "has_config": (plugin_dir / "config.json").exists(),
                                "is_installed": True
                            })
        return plugins

    def _is_plugin_installed(self, plugin_name: str, author: str) -> bool:
        """检查插件是否已安装"""
        plugin_dir = self.store_dir / author / plugin_name
        return (plugin_dir / "main.py").exists()

    def _find_plugin_dir(self, plugin_name: str) -> Path | None:
        """查找插件目录"""
        if not self.store_dir.exists():
            return None
        for author_dir in self.store_dir.iterdir():
            if author_dir.is_dir():
                plugin_dir = author_dir / plugin_name
                if plugin_dir.exists() and (plugin_dir / "main.py").exists():
                    return plugin_dir
        return None

    def _load_config_schema(self, plugin_name: str) -> dict:
        """加载插件 config.json schema"""
        plugin_dir = self._find_plugin_dir(plugin_name)
        if not plugin_dir:
            return {}
        schema_path = plugin_dir / "config.json"
        if not schema_path.exists():
            return {}
        with open(schema_path, 'r', encoding='utf-8') as f:
            return json.load(f)

    def _load_plugin_config(self, plugin_name: str) -> dict:
        """加载插件当前配置"""
        schema = self._load_config_schema(plugin_name)
        defaults = {}
        for key, field_def in schema.items():
            defaults[key] = field_def.get("default")
        if self.storage:
            storage_instance = self.storage.get_storage("pkg-manager")
            user_config = storage_instance.get(f"plugin_config.{plugin_name}", {})
            defaults.update(user_config)
        return defaults

    def _save_plugin_config(self, plugin_name: str, config: dict):
        """保存插件配置"""
        if self.storage:
            storage_instance = self.storage.get_storage("pkg-manager")
            storage_instance.set(f"plugin_config.{plugin_name}", config)

    def _get_plugin_detailed_info(self, plugin_name: str) -> dict:
        """获取插件的依赖、事件、页面信息"""
        dependencies = []
        events = []  # 事件 = 功能描述
        plugin_dir = self._find_plugin_dir(plugin_name)
        
        if plugin_dir:
            manifest_path = plugin_dir / "manifest.json"
            if manifest_path.exists():
                with open(manifest_path, 'r', encoding='utf-8') as f:
                    manifest = json.load(f)
                dependencies = manifest.get("dependencies", [])
                # 从 manifest 的 metadata.description 或 type 中提取功能
                metadata = manifest.get("metadata", {})
                plugin_type = metadata.get("type", "")
                if plugin_type:
                    events.append(f"类型: {plugin_type}")
                # 从 manifest config 推断功能
                config = manifest.get("config", {})
                if config.get("enabled"):
                    events.append("已启用")

        # 只返回该插件自己注册的页面（通过插件名匹配）
        pages = []
        if self.webui and hasattr(self.webui, 'server') and self.webui.server:
            for path, provider in self.webui.server.pages.items():
                # 检查 provider 是否属于该插件
                provider_name = getattr(provider, '__self__', None)
                if provider_name and isinstance(provider_name, PkgManagerPlugin):
                    continue  # 跳过自己的页面
                # 通过路径前缀判断（dashboard 注册 /dashboard）
                if path == f'/{plugin_name}' or path.startswith(f'/{plugin_name}/'):
                    pages.append({"path": path})
                # 特殊处理：首页
                if plugin_name == 'webui' and path == '/':
                    pages.append({"path": path})

        return {
            "name": plugin_name,
            "dependencies": dependencies,
            "config_fields": list(self._load_config_schema(plugin_name).keys()),
            "pages": pages,
            "events": events
        }


register_plugin_type("PkgManagerPlugin", PkgManagerPlugin)


def New():
    return PkgManagerPlugin()
