# -*- coding: utf-8 -*-
"""CJ DiffCommand 测试（Phase 8 Tier 2）

借鉴 zhikuncode DiffCommand.java：
- /diff [staged] 显示 Git 工作区或暂存区差异
- 检测当前目录是否 git 仓库
- 截断 10000 字符避免刷屏
- 同时返回 stat 摘要
"""
import subprocess
from pathlib import Path
from unittest.mock import patch, MagicMock

import pytest

from abyss.commands.diff import (
    handle_diff,
    is_git_repo,
    MAX_DIFF_OUTPUT_CHARS,
    run_git_diff,
    run_git_stat,
)


class TestIsGitRepo:
    """is_git_repo 测试"""

    def test_returns_true_in_git_repo(self, tmp_path):
        """在 git 仓库内返回 True"""
        # init a git repo
        subprocess.run(["git", "init"], cwd=str(tmp_path), capture_output=True)
        subprocess.run(["git", "config", "user.email", "test@test.com"], cwd=str(tmp_path), capture_output=True)
        subprocess.run(["git", "config", "user.name", "test"], cwd=str(tmp_path), capture_output=True)
        assert is_git_repo(str(tmp_path)) is True

    def test_returns_false_in_non_git_dir(self, tmp_path):
        """非 git 目录返回 False"""
        assert is_git_repo(str(tmp_path)) is False

    def test_returns_false_for_nonexistent_dir(self):
        """不存在的目录返回 False"""
        assert is_git_repo("Z:/nonexistent/path/xyz") is False


class TestRunGitDiff:
    """run_git_diff 测试"""

    def test_unstaged_calls_git_diff(self, tmp_path):
        """unstaged 调用 git diff"""
        subprocess.run(["git", "init"], cwd=str(tmp_path), capture_output=True)
        # 创建文件并 commit
        (tmp_path / "a.txt").write_text("initial", encoding="utf-8")
        subprocess.run(["git", "add", "."], cwd=str(tmp_path), capture_output=True)
        subprocess.run(["git", "commit", "-m", "init"], cwd=str(tmp_path), capture_output=True)
        # 修改文件
        (tmp_path / "a.txt").write_text("modified", encoding="utf-8")
        out, err = run_git_diff(str(tmp_path), staged=False)
        assert "modified" in out or "initial" in out

    def test_staged_calls_git_diff_cached(self, tmp_path):
        """staged 调用 git diff --cached"""
        subprocess.run(["git", "init"], cwd=str(tmp_path), capture_output=True)
        subprocess.run(["git", "config", "user.email", "t@t.com"], cwd=str(tmp_path), capture_output=True)
        subprocess.run(["git", "config", "user.name", "t"], cwd=str(tmp_path), capture_output=True)
        (tmp_path / "a.txt").write_text("initial", encoding="utf-8")
        subprocess.run(["git", "add", "."], cwd=str(tmp_path), capture_output=True)
        subprocess.run(["git", "commit", "-m", "init"], cwd=str(tmp_path), capture_output=True)
        # 修改并 stage
        (tmp_path / "a.txt").write_text("staged modification", encoding="utf-8")
        subprocess.run(["git", "add", "a.txt"], cwd=str(tmp_path), capture_output=True)
        out, err = run_git_diff(str(tmp_path), staged=True)
        assert "staged modification" in out


class TestRunGitStat:
    """run_git_stat 测试"""

    def test_returns_stat_output(self, tmp_path):
        """返回 stat 摘要"""
        subprocess.run(["git", "init"], cwd=str(tmp_path), capture_output=True)
        subprocess.run(["git", "config", "user.email", "t@t.com"], cwd=str(tmp_path), capture_output=True)
        subprocess.run(["git", "config", "user.name", "t"], cwd=str(tmp_path), capture_output=True)
        (tmp_path / "a.txt").write_text("initial", encoding="utf-8")
        subprocess.run(["git", "add", "."], cwd=str(tmp_path), capture_output=True)
        subprocess.run(["git", "commit", "-m", "init"], cwd=str(tmp_path), capture_output=True)
        (tmp_path / "a.txt").write_text("modified content", encoding="utf-8")
        out, _ = run_git_stat(str(tmp_path))
        assert "a.txt" in out


class TestHandleDiff:
    """handle_diff 测试"""

    def test_not_git_repo_returns_error(self, tmp_path):
        """非 git 仓库返回错误消息"""
        result = handle_diff(str(tmp_path), staged=False)
        assert "不是 Git 仓库" in result or "not a git" in result.lower()

    def test_returns_diff_output_for_unstaged(self, tmp_path):
        """unstaged 返回 diff"""
        subprocess.run(["git", "init"], cwd=str(tmp_path), capture_output=True)
        subprocess.run(["git", "config", "user.email", "t@t.com"], cwd=str(tmp_path), capture_output=True)
        subprocess.run(["git", "config", "user.name", "t"], cwd=str(tmp_path), capture_output=True)
        (tmp_path / "a.txt").write_text("initial", encoding="utf-8")
        subprocess.run(["git", "add", "."], cwd=str(tmp_path), capture_output=True)
        subprocess.run(["git", "commit", "-m", "init"], cwd=str(tmp_path), capture_output=True)
        (tmp_path / "a.txt").write_text("modified content", encoding="utf-8")
        result = handle_diff(str(tmp_path), staged=False)
        assert "modified content" in result or "initial" in result

    def test_returns_diff_output_for_staged(self, tmp_path):
        """staged 返回 cached diff"""
        subprocess.run(["git", "init"], cwd=str(tmp_path), capture_output=True)
        subprocess.run(["git", "config", "user.email", "t@t.com"], cwd=str(tmp_path), capture_output=True)
        subprocess.run(["git", "config", "user.name", "t"], cwd=str(tmp_path), capture_output=True)
        (tmp_path / "a.txt").write_text("initial", encoding="utf-8")
        subprocess.run(["git", "add", "."], cwd=str(tmp_path), capture_output=True)
        subprocess.run(["git", "commit", "-m", "init"], cwd=str(tmp_path), capture_output=True)
        (tmp_path / "a.txt").write_text("staged content", encoding="utf-8")
        subprocess.run(["git", "add", "a.txt"], cwd=str(tmp_path), capture_output=True)
        result = handle_diff(str(tmp_path), staged=True)
        assert "staged content" in result

    def test_output_truncated_at_max(self, tmp_path):
        """超过 MAX_DIFF_OUTPUT_CHARS 时截断"""
        subprocess.run(["git", "init"], cwd=str(tmp_path), capture_output=True)
        subprocess.run(["git", "config", "user.email", "t@t.com"], cwd=str(tmp_path), capture_output=True)
        subprocess.run(["git", "config", "user.name", "t"], cwd=str(tmp_path), capture_output=True)
        (tmp_path / "a.txt").write_text("initial", encoding="utf-8")
        subprocess.run(["git", "add", "."], cwd=str(tmp_path), capture_output=True)
        subprocess.run(["git", "commit", "-m", "init"], cwd=str(tmp_path), capture_output=True)
        # 构造超长 diff
        (tmp_path / "a.txt").write_text("x" * (MAX_DIFF_OUTPUT_CHARS + 1000), encoding="utf-8")
        result = handle_diff(str(tmp_path), staged=False)
        assert "截断" in result or "truncated" in result.lower()

    def test_includes_stat_summary(self, tmp_path):
        """结果包含 stat 摘要"""
        subprocess.run(["git", "init"], cwd=str(tmp_path), capture_output=True)
        subprocess.run(["git", "config", "user.email", "t@t.com"], cwd=str(tmp_path), capture_output=True)
        subprocess.run(["git", "config", "user.name", "t"], cwd=str(tmp_path), capture_output=True)
        (tmp_path / "a.txt").write_text("initial", encoding="utf-8")
        subprocess.run(["git", "add", "."], cwd=str(tmp_path), capture_output=True)
        subprocess.run(["git", "commit", "-m", "init"], cwd=str(tmp_path), capture_output=True)
        (tmp_path / "a.txt").write_text("modified content here", encoding="utf-8")
        result = handle_diff(str(tmp_path), staged=False)
        assert "a.txt" in result  # stat 中应包含文件名

    def test_no_changes_returns_info_message(self, tmp_path):
        """无变更时返回提示消息"""
        subprocess.run(["git", "init"], cwd=str(tmp_path), capture_output=True)
        subprocess.run(["git", "config", "user.email", "t@t.com"], cwd=str(tmp_path), capture_output=True)
        subprocess.run(["git", "config", "user.name", "t"], cwd=str(tmp_path), capture_output=True)
        (tmp_path / "a.txt").write_text("initial", encoding="utf-8")
        subprocess.run(["git", "add", "."], cwd=str(tmp_path), capture_output=True)
        subprocess.run(["git", "commit", "-m", "init"], cwd=str(tmp_path), capture_output=True)
        result = handle_diff(str(tmp_path), staged=False)
        assert "无变更" in result or "no changes" in result.lower()
