"""
WorkspaceStore 抽象定义

用于管理 Git 工作区文件的版本控制。
"""

from abc import ABC, abstractmethod
from dataclasses import dataclass
from datetime import datetime
from typing import Optional, List


@dataclass
class FileInfo:
    """文件信息"""
    path: str
    is_file: bool
    size: int
    modified: datetime
    commit_hash: Optional[str] = None
    commit_message: Optional[str] = None


@dataclass
class CommitInfo:
    """提交信息"""
    hash: str
    message: str
    author: str
    email: Optional[str]
    timestamp: datetime
    files_changed: List[str]


@dataclass
class TagInfo:
    """标签信息"""
    name: str
    commit_hash: str
    message: Optional[str]
    created_at: Optional[datetime]


class WorkspaceStore(ABC):
    """
    工作区 Git 版本管理抽象基类。
    
    管理用户编辑的文件，包括：
    - 代码文件
    - 配置文件
    - Agent 生成的文件
    
    每个工作区对应一个 Git 仓库。
    """
    
    def __init__(self, workspace_id: str, user_id: str):
        self.workspace_id = workspace_id
        self.user_id = user_id
    
    # ===== 文件操作 =====
    
    @abstractmethod
    async def read_file(self, path: str, ref: str = "HEAD") -> bytes:
        """
        读取文件内容。
        
        Args:
            path: 文件相对路径（相对于工作区根目录）
            ref: 版本引用（HEAD, commit_hash, branch, tag）
            
        Returns:
            文件内容
        """
        pass
    
    @abstractmethod
    async def write_file(
        self,
        path: str,
        content: bytes,
        commit_msg: Optional[str] = None
    ) -> str:
        """
        写入文件。
        
        Args:
            path: 文件相对路径
            content: 文件内容
            commit_msg: 提交信息，为 None 时不自动提交
            
        Returns:
            如果提交了，返回 commit hash；否则返回空字符串
        """
        pass
    
    @abstractmethod
    async def delete_file(
        self,
        path: str,
        commit_msg: Optional[str] = None
    ) -> bool:
        """
        删除文件。
        
        Args:
            path: 文件相对路径
            commit_msg: 提交信息，为 None 时不自动提交
            
        Returns:
            是否删除成功
        """
        pass
    
    @abstractmethod
    async def exists(self, path: str, ref: str = "HEAD") -> bool:
        """
        检查文件是否存在。
        
        Args:
            path: 文件相对路径
            ref: 版本引用
            
        Returns:
            文件是否存在
        """
        pass
    
    # ===== 目录操作 =====
    
    @abstractmethod
    async def list_files(
        self,
        path: str = "",
        ref: str = "HEAD",
        recursive: bool = False
    ) -> List[FileInfo]:
        """
        列出目录文件。
        
        Args:
            path: 目录相对路径，空字符串表示根目录
            ref: 版本引用
            recursive: 是否递归列出子目录
            
        Returns:
            文件信息列表
        """
        pass
    
    @abstractmethod
    async def create_directory(self, path: str) -> bool:
        """
        创建目录。
        
        Args:
            path: 目录相对路径
            
        Returns:
            是否创建成功
        """
        pass
    
    @abstractmethod
    async def delete_directory(
        self,
        path: str,
        recursive: bool = False
    ) -> bool:
        """
        删除目录。
        
        Args:
            path: 目录相对路径
            recursive: 是否递归删除
            
        Returns:
            是否删除成功
        """
        pass
    
    # ===== 版本管理 =====
    
    @abstractmethod
    async def commit(
        self,
        message: str,
        files: Optional[List[str]] = None
    ) -> str:
        """
        提交更改。
        
        Args:
            message: 提交信息
            files: 指定提交的文件列表，None 表示提交所有更改
            
        Returns:
            commit hash
        """
        pass
    
    @abstractmethod
    async def log(
        self,
        path: Optional[str] = None,
        n: int = 20
    ) -> List[CommitInfo]:
        """
        查看提交历史。
        
        Args:
            path: 特定文件的历史，None 表示所有提交
            n: 返回数量
            
        Returns:
            提交信息列表
        """
        pass
    
    @abstractmethod
    async def diff(
        self,
        path: Optional[str] = None,
        from_ref: str = "HEAD~1",
        to_ref: str = "HEAD"
    ) -> str:
        """
        对比版本差异。
        
        Args:
            path: 特定文件的差异，None 表示所有文件
            from_ref: 起始版本
            to_ref: 结束版本
            
        Returns:
            diff 文本
        """
        pass
    
    @abstractmethod
    async def rollback(
        self,
        path: str,
        commit_hash: str
    ) -> bool:
        """
        回退文件到指定版本。
        
        Args:
            path: 文件相对路径
            commit_hash: 目标版本 commit hash
            
        Returns:
            是否回退成功
        """
        pass
    
    @abstractmethod
    async def reset(
        self,
        commit_hash: str,
        hard: bool = False
    ) -> bool:
        """
        重置整个工作区到指定版本。
        
        Args:
            commit_hash: 目标版本
            hard: 是否硬重置（丢弃所有更改）
            
        Returns:
            是否重置成功
        """
        pass
    
    # ===== 分支/标签 =====
    
    @abstractmethod
    async def create_branch(
        self,
        branch: str,
        from_ref: str = "HEAD"
    ) -> bool:
        """
        创建分支。
        
        Args:
            branch: 分支名
            from_ref: 起始版本
            
        Returns:
            是否创建成功
        """
        pass
    
    @abstractmethod
    async def switch_branch(self, branch: str) -> bool:
        """
        切换分支。
        
        Args:
            branch: 分支名
            
        Returns:
            是否切换成功
        """
        pass
    
    @abstractmethod
    async def list_branches(self) -> List[str]:
        """
        列出所有分支。
        
        Returns:
            分支名列表
        """
        pass
    
    @abstractmethod
    async def current_branch(self) -> str:
        """
        获取当前分支。
        
        Returns:
            当前分支名
        """
        pass
    
    @abstractmethod
    async def tag(
        self,
        name: str,
        commit_hash: Optional[str] = None,
        message: Optional[str] = None
    ) -> bool:
        """
        创建标签。
        
        Args:
            name: 标签名
            commit_hash: 目标 commit，None 表示当前 HEAD
            message: 标签信息
            
        Returns:
            是否创建成功
        """
        pass
    
    @abstractmethod
    async def list_tags(self) -> List[TagInfo]:
        """
        列出所有标签。
        
        Returns:
            标签信息列表
        """
        pass
    
    @abstractmethod
    async def delete_tag(self, name: str) -> bool:
        """
        删除标签。
        
        Args:
            name: 标签名
            
        Returns:
            是否删除成功
        """
        pass
    
    # ===== 工作区操作 =====
    
    @abstractmethod
    async def upload_workspace(
        self,
        zip_data: bytes,
        commit_msg: Optional[str] = None
    ) -> str:
        """
        上传整个工作区（zip 包）。
        
        Args:
            zip_data: zip 文件数据
            commit_msg: 提交信息
            
        Returns:
            commit hash
        """
        pass
    
    @abstractmethod
    async def download_workspace(
        self,
        ref: str = "HEAD",
        format: str = "zip"
    ) -> bytes:
        """
        打包下载整个工作区。
        
        Args:
            ref: 版本引用
            format: 打包格式（zip）
            
        Returns:
            打包后的数据
        """
        pass
    
    @abstractmethod
    async def delete_workspace(self) -> bool:
        """
        删除整个工作区（Git 仓库）。
        
        Returns:
            是否删除成功
        """
        pass
    
    @abstractmethod
    async def get_status(self) -> dict:
        """
        获取工作区状态。
        
        Returns:
            包含以下字段的字典：
            - modified: 修改的文件列表
            - added: 新增的文件列表
            - deleted: 删除的文件列表
            - untracked: 未跟踪的文件列表
        """
        pass
