"""
浏览器配置持久化管理

支持保存和加载完整的浏览器配置，包括：
- Cookies
- LocalStorage / SessionStorage
- 配置信息
- 浏览器状态

示例:
    async with EasyBrowser() as browser:
        # 保存配置
        profile = BrowserProfile("my_session")
        await profile.save(browser)

        # 加载配置
        await profile.load(browser)

        # 列出所有配置
        profiles = BrowserProfile.list_profiles()
"""
import json
import shutil
from pathlib import Path
from typing import Optional, List, Dict, Any, TYPE_CHECKING
from datetime import datetime
from loguru import logger

if TYPE_CHECKING:
    from .browser import EasyBrowser


class BrowserProfile:
    """
    浏览器配置管理

    管理浏览器会话的持久化存储，包括 cookies、storage 和配置。
    """

    def __init__(self, name: str, storage_dir: str = "./profiles"):
        """
        初始化配置管理器

        Args:
            name: 配置名称（用于标识不同会话）
            storage_dir: 存储目录
        """
        self.name = name
        self.storage_dir = Path(storage_dir)
        self.profile_dir = self.storage_dir / name

    @property
    def config_file(self) -> Path:
        """配置文件路径"""
        return self.profile_dir / "config.json"

    @property
    def cookies_file(self) -> Path:
        """Cookies 文件路径"""
        return self.profile_dir / "cookies.json"

    @property
    def storage_file(self) -> Path:
        """Storage 文件路径"""
        return self.profile_dir / "storage.json"

    @property
    def state_file(self) -> Path:
        """状态文件路径"""
        return self.profile_dir / "state.json"

    def exists(self) -> bool:
        """检查配置是否存在"""
        return self.profile_dir.exists()

    async def save(self, browser: "EasyBrowser") -> None:
        """
        保存完整配置

        保存内容包括：
        - 浏览器配置
        - Cookies
        - LocalStorage
        - SessionStorage
        - 当前 URL

        Args:
            browser: EasyBrowser 实例
        """
        # 创建配置目录
        self.profile_dir.mkdir(parents=True, exist_ok=True)

        # 保存配置
        self._save_config(browser.config)

        # 保存 Cookies
        await self._save_cookies(browser)

        # 保存 Storage
        await self._save_storage(browser)

        # 保存状态
        await self._save_state(browser)

        logger.info(f"配置已保存: {self.name}")

    async def load(self, browser: "EasyBrowser") -> bool:
        """
        加载完整配置

        Args:
            browser: EasyBrowser 实例

        Returns:
            bool: 是否成功加载
        """
        if not self.exists():
            logger.warning(f"配置不存在: {self.name}")
            return False

        try:
            # 加载配置
            self._load_config(browser.config)

            # 加载 Cookies
            await self._load_cookies(browser)

            # 加载 Storage
            await self._load_storage(browser)

            logger.info(f"配置已加载: {self.name}")
            return True
        except Exception as e:
            logger.error(f"加载配置失败: {e}")
            return False

    async def save_cookies(self, browser: "EasyBrowser") -> None:
        """仅保存 Cookies"""
        self.profile_dir.mkdir(parents=True, exist_ok=True)
        await self._save_cookies(browser)
        logger.info(f"Cookies 已保存: {self.name}")

    async def load_cookies(self, browser: "EasyBrowser") -> bool:
        """仅加载 Cookies"""
        if not self.cookies_file.exists():
            return False
        return await self._load_cookies(browser)

    async def save_storage(self, browser: "EasyBrowser") -> None:
        """仅保存 Storage"""
        self.profile_dir.mkdir(parents=True, exist_ok=True)
        await self._save_storage(browser)
        logger.info(f"Storage 已保存: {self.name}")

    async def load_storage(self, browser: "EasyBrowser") -> bool:
        """仅加载 Storage"""
        if not self.storage_file.exists():
            return False
        return await self._load_storage(browser)

    def delete(self) -> bool:
        """
        删除配置

        Returns:
            bool: 是否成功删除
        """
        if not self.exists():
            return False

        try:
            shutil.rmtree(self.profile_dir)
            logger.info(f"配置已删除: {self.name}")
            return True
        except Exception as e:
            logger.error(f"删除配置失败: {e}")
            return False

    def get_info(self) -> Optional[Dict[str, Any]]:
        """
        获取配置信息

        Returns:
            配置信息字典
        """
        if not self.exists():
            return None

        info = {
            "name": self.name,
            "path": str(self.profile_dir),
            "has_cookies": self.cookies_file.exists(),
            "has_storage": self.storage_file.exists(),
            "has_config": self.config_file.exists(),
        }

        # 获取创建时间
        stat = self.profile_dir.stat()
        info["created_at"] = datetime.fromtimestamp(stat.st_ctime).isoformat()
        info["modified_at"] = datetime.fromtimestamp(stat.st_mtime).isoformat()

        return info

    # ==================== 内部方法 ====================

    def _save_config(self, config) -> None:
        """保存浏览器配置"""
        config_data = config.to_dict()
        with open(self.config_file, "w", encoding="utf-8") as f:
            json.dump(config_data, f, indent=2, ensure_ascii=False)

    def _load_config(self, config) -> None:
        """加载浏览器配置"""
        if not self.config_file.exists():
            return

        with open(self.config_file, "r", encoding="utf-8") as f:
            data = json.load(f)

        # 更新配置
        for key, value in data.items():
            if hasattr(config, key):
                setattr(config, key, value)

    async def _save_cookies(self, browser: "EasyBrowser") -> None:
        """保存 Cookies"""
        cookies = await browser.cookies.get_all()
        with open(self.cookies_file, "w", encoding="utf-8") as f:
            json.dump(cookies, f, indent=2, ensure_ascii=False)

    async def _load_cookies(self, browser: "EasyBrowser") -> bool:
        """加载 Cookies"""
        if not self.cookies_file.exists():
            return False

        with open(self.cookies_file, "r", encoding="utf-8") as f:
            cookies = json.load(f)

        await browser.cookies.set_all(cookies)
        return True

    async def _save_storage(self, browser: "EasyBrowser") -> None:
        """保存 Storage"""
        page = browser.page

        # 获取 LocalStorage
        local_storage = await page.evaluate("() => Object.assign({}, localStorage)")

        # 获取 SessionStorage
        session_storage = await page.evaluate("() => Object.assign({}, sessionStorage)")

        storage_data = {
            "local_storage": local_storage,
            "session_storage": session_storage,
        }

        with open(self.storage_file, "w", encoding="utf-8") as f:
            json.dump(storage_data, f, indent=2, ensure_ascii=False)

    async def _load_storage(self, browser: "EasyBrowser") -> bool:
        """加载 Storage"""
        if not self.storage_file.exists():
            return False

        with open(self.storage_file, "r", encoding="utf-8") as f:
            storage_data = json.load(f)

        page = browser.page

        # 恢复 LocalStorage
        local_storage = storage_data.get("local_storage", {})
        for key, value in local_storage.items():
            await page.evaluate(
                f"() => localStorage.setItem('{key}', '{value}')"
            )

        # 恢复 SessionStorage
        session_storage = storage_data.get("session_storage", {})
        for key, value in session_storage.items():
            await page.evaluate(
                f"() => sessionStorage.setItem('{key}', '{value}')"
            )

        return True

    async def _save_state(self, browser: "EasyBrowser") -> None:
        """保存浏览器状态"""
        page = browser.page

        state = {
            "url": page.url,
            "title": await page.title(),
            "saved_at": datetime.now().isoformat(),
        }

        with open(self.state_file, "w", encoding="utf-8") as f:
            json.dump(state, f, indent=2, ensure_ascii=False)

    # ==================== 类方法 ====================

    @classmethod
    def list_profiles(cls, storage_dir: str = "./profiles") -> List["BrowserProfile"]:
        """
        列出所有配置

        Args:
            storage_dir: 存储目录

        Returns:
            List[BrowserProfile]: 配置列表
        """
        storage_path = Path(storage_dir)
        if not storage_path.exists():
            return []

        profiles = []
        for item in storage_path.iterdir():
            if item.is_dir():
                profiles.append(cls(item.name, storage_dir))

        return profiles

    @classmethod
    def profile_exists(cls, name: str, storage_dir: str = "./profiles") -> bool:
        """
        检查配置是否存在

        Args:
            name: 配置名称
            storage_dir: 存储目录

        Returns:
            bool: 是否存在
        """
        profile = cls(name, storage_dir)
        return profile.exists()

    @classmethod
    def delete_profile(cls, name: str, storage_dir: str = "./profiles") -> bool:
        """
        删除配置

        Args:
            name: 配置名称
            storage_dir: 存储目录

        Returns:
            bool: 是否成功删除
        """
        profile = cls(name, storage_dir)
        return profile.delete()

    @classmethod
    def clear_all(cls, storage_dir: str = "./profiles") -> None:
        """
        清除所有配置

        Args:
            storage_dir: 存储目录
        """
        storage_path = Path(storage_dir)
        if storage_path.exists():
            shutil.rmtree(storage_path)
            logger.info(f"所有配置已清除: {storage_dir}")


class ProfileManager:
    """
    配置管理器

    提供统一的配置管理接口。
    """

    def __init__(self, storage_dir: str = "./profiles"):
        """
        初始化配置管理器

        Args:
            storage_dir: 存储目录
        """
        self.storage_dir = storage_dir
        self._profiles: Dict[str, BrowserProfile] = {}

    def get_profile(self, name: str) -> BrowserProfile:
        """
        获取配置

        Args:
            name: 配置名称

        Returns:
            BrowserProfile: 配置实例
        """
        if name not in self._profiles:
            self._profiles[name] = BrowserProfile(name, self.storage_dir)
        return self._profiles[name]

    async def save_profile(self, name: str, browser: "EasyBrowser") -> None:
        """
        保存配置

        Args:
            name: 配置名称
            browser: EasyBrowser 实例
        """
        profile = self.get_profile(name)
        await profile.save(browser)

    async def load_profile(self, name: str, browser: "EasyBrowser") -> bool:
        """
        加载配置

        Args:
            name: 配置名称
            browser: EasyBrowser 实例

        Returns:
            bool: 是否成功加载
        """
        profile = self.get_profile(name)
        return await profile.load(browser)

    def list_profiles(self) -> List[str]:
        """
        列出所有配置名称

        Returns:
            List[str]: 配置名称列表
        """
        profiles = BrowserProfile.list_profiles(self.storage_dir)
        return [p.name for p in profiles]

    def delete_profile(self, name: str) -> bool:
        """
        删除配置

        Args:
            name: 配置名称

        Returns:
            bool: 是否成功删除
        """
        if name in self._profiles:
            del self._profiles[name]
        return BrowserProfile.delete_profile(name, self.storage_dir)

    def get_profile_info(self, name: str) -> Optional[Dict[str, Any]]:
        """
        获取配置信息

        Args:
            name: 配置名称

        Returns:
            配置信息字典
        """
        profile = self.get_profile(name)
        return profile.get_info()
