#!/usr/bin/env python3
"""CODEMAP自動更新用Post-commitフック

仕様書: SPEC-CODEMAP-AUTO-UPDATE-001
REQ-3: Git統合機能
"""

import os
import shutil
import sys
from pathlib import Path

# プロジェクトルートをsys.pathに追加
project_root = Path(__file__).parent.parent.parent.parent
sys.path.insert(0, str(project_root))

from noveler.application.use_cases.codemap_auto_update_use_case import (
    CodeMapAutoUpdateRequest,
    CodeMapAutoUpdateUseCase,
)
from noveler.domain.services.codemap_synchronization_service import CodeMapSynchronizationService
from noveler.infrastructure.adapters.git_information_adapter import GitInformationAdapter
from noveler.infrastructure.repositories.yaml_codemap_repository import YamlCodeMapRepository

# DDD準拠: Infrastructure→Presentation依存を除去
from noveler.presentation.shared.shared_utilities import console


class CodeMapPostCommitHook:
    """CODEMAP自動更新Post-commitフック

    Git post-commit hookから呼び出される統合機能
    """

    def __init__(self, repository_path: Path | None = None, logger_service: object | None = None, console_service: object | None = None) -> None:
        """初期化

        Args:
            repository_path: リポジトリパス（Noneの場合は現在のディレクトリ）
            logger_service: ロガーサービス
            console_service: コンソールサービス
        """
        self.repository_path = repository_path or Path.cwd()

        # CODEMAPパスの確定
        self.codemap_path = self.repository_path / "CODEMAP.yaml"

        # 依存性の初期化
        self._initialize_dependencies()

        self.logger_service = logger_service
        # コンソールサービスが未指定の場合は共有Consoleにフォールバック
        self.console_service = console_service or console
    def _initialize_dependencies(self) -> None:
        """依存性の初期化"""
        # リポジトリとアダプターの初期化
        self.codemap_repository = YamlCodeMapRepository(self.codemap_path)
        self.git_adapter = GitInformationAdapter(self.repository_path)
        self.sync_service = CodeMapSynchronizationService()

        # ユースケースの初期化
        self.use_case = CodeMapAutoUpdateUseCase(self.codemap_repository, self.git_adapter, self.sync_service)

    def execute(self, force_update: bool = False, skip_validation: bool = False) -> bool:
        """CODEMAP自動更新実行

        Args:
            force_update: 強制更新フラグ
            skip_validation: 検証スキップフラグ

        Returns:
            bool: 実行成功時True
        """
        try:
            self.console_service.print("🔄 CODEMAP auto-update starting...")

            # リクエスト作成
            request = CodeMapAutoUpdateRequest(
                force_update=force_update, create_backup=True, validate_result=not skip_validation
            )

            # 自動更新実行
            response = self.use_case.execute(request)

            # 結果の処理
            if response.success:
                if response.updated:
                    self.console_service.print("✅ CODEMAP updated successfully")
                    self.console_service.print(f"📝 Changes: {response.changes_summary}")
                    if response.backup_id:
                        self.console_service.print(f"💾 Backup: {response.backup_id}")
                else:
                    self.console_service.print("ℹ️ CODEMAP is already up-to-date")

                self.console_service.print(f"⏱️ Execution time: {response.execution_time_ms:.1f}ms")
                return True
            self.console_service.print(f"❌ CODEMAP update failed: {response.error_message}")
            if response.validation_errors:
                self.console_service.print("Validation errors:")
                for error in response.validation_errors:
                    self.console_service.print(f"  - {error}")
            return False

        except Exception as e:
            self.console_service.print(f"❌ Hook execution error: {e}")
            return False

    def get_status(self) -> dict:
        """更新システムの状態取得

        Returns:
            dict: システム状態情報
        """
        try:
            return self.use_case.get_update_status()
        except Exception as e:
            return {"error": str(e), "codemap_available": False, "git_repository": False}


def main() -> int:
    """メイン実行関数

    Git post-commit hookから呼び出される

    Returns:
        int: 終了コード（0: 成功, 1: 失敗）
    """
    try:
        # 現在のディレクトリをリポジトリルートとして使用
        hook = CodeMapPostCommitHook()

        # システム状態の確認
        status = hook.get_status()

        if not status.get("git_repository", False):
            console.print("[yellow]⚠️ Not a Git repository, skipping CODEMAP update[/yellow]")
            return 0

        if not status.get("codemap_available", False):
            console.print("[yellow]⚠️ CODEMAP not found, skipping update[/yellow]")
            return 0

        # 自動更新実行
        success = hook.execute()

        return 0 if success else 1

    except KeyboardInterrupt:
        console.print("[yellow]⚠️ CODEMAP update interrupted[/yellow]")
        return 1
    except Exception as e:
        console.print(f"[red]❌ Unexpected error: {e}[/red]")
        return 1


# フック統合のための関数エクスポート
def install_codemap_post_commit_hook(git_root: Path, guide_root: Path | None = None) -> bool:
    """CODEMAP post-commit hookのインストール

    Args:
        git_root: GitリポジトリのルートPath
        guide_root: ガイドプロジェクトのルートPath（省略時はgit_rootを使用）

    Returns:
        bool: インストール成功時True
    """
    try:
        hooks_dir = git_root / ".git" / "hooks"
        # フォールバック: guide_root未指定の場合は、このファイルのリポジトリルートを推定
        guide_root = guide_root or Path(__file__).resolve().parents[5]
        hook_file = hooks_dir / "post-commit"

        def _to_posix(path: Path) -> str:
            """Convert platform specific path to POSIX style for shell scripts."""
            return path.as_posix()

        def _to_msys(path: Path) -> str:
            """Convert Windows paths to MSYS compatible absolute paths."""
            posix = path.as_posix()
            if len(posix) >= 2 and posix[1] == ":":
                drive = posix[0].lower()
                remainder = posix[2:] if len(posix) > 2 else ""
                if not remainder.startswith("/"):
                    remainder = "/" + remainder
                return f"/{drive}{remainder}"
            return posix

        def _to_wsl(path: Path) -> str:
            """Convert Windows paths to WSL mount style paths."""
            posix = path.as_posix()
            if len(posix) >= 2 and posix[1] == ":":
                drive = posix[0].lower()
                remainder = posix[2:] if len(posix) > 2 else ""
                if not remainder.startswith("/"):
                    remainder = "/" + remainder
                return f"/mnt/{drive}{remainder}"
            return posix

        posix_git_root = _to_posix(git_root)
        posix_src_path = _to_posix(guide_root / "src")
        posix_original_hook = _to_posix(hooks_dir / "post-commit.original")
        posix_script_path = _to_posix(guide_root / "src" / "noveler" / "infrastructure" / "git" / "hooks" / "codemap_post_commit_hook.py")

        if os.name == "nt":
            msys_git_root = _to_msys(git_root)
            msys_src_path = _to_msys(guide_root / "src")
            msys_original_hook = _to_msys(hooks_dir / "post-commit.original")
            msys_script_path = _to_msys(guide_root / "src" / "noveler" / "infrastructure" / "git" / "hooks" / "codemap_post_commit_hook.py")
            wsl_git_root = _to_wsl(git_root)
            wsl_src_path = _to_wsl(guide_root / "src")
            wsl_original_hook = _to_wsl(hooks_dir / "post-commit.original")
            wsl_script_path = _to_wsl(guide_root / "src" / "noveler" / "infrastructure" / "git" / "hooks" / "codemap_post_commit_hook.py")
        else:
            msys_git_root = posix_git_root
            msys_src_path = posix_src_path
            msys_original_hook = posix_original_hook
            msys_script_path = posix_script_path
            wsl_git_root = posix_git_root
            wsl_src_path = posix_src_path
            wsl_original_hook = posix_original_hook
            wsl_script_path = posix_script_path

        # フック内容の生成
        hook_content = f"""#!/bin/sh
# CODEMAP Auto-Update Post-Commit Hook
# Generated by Claude Code Development Guidelines

# Python環境の確認
UNAME_OUT="$(uname 2>/dev/null || echo unknown)"
if echo "$UNAME_OUT" | grep -qi "linux" && [ -d "/mnt" ]; then
    PYTHON_CANDIDATES="python3 python py python.exe"
else
    PYTHON_CANDIDATES="python.exe py python3 python"
fi

PYTHON_CMD=""
for candidate in $PYTHON_CANDIDATES; do
    if command -v $candidate >/dev/null 2>&1; then
        if [ "$candidate" = "py" ]; then
            PYTHON_CMD="py -3"
        else
            PYTHON_CMD="$candidate"
        fi
        break
    fi
done

if [ -z "$PYTHON_CMD" ]; then
    echo "Warning: Python not found, skipping CODEMAP update"
    exit 0
fi

# Windows/MSYS 環境向けにパスを変換
if echo "$UNAME_OUT" | grep -qi "mingw"; then
    REPO_PATH="{msys_git_root}"
    SRC_PATH="{msys_src_path}"
    HOOK_ORIGINAL_PATH="{msys_original_hook}"
    PYTHON_SCRIPT_PATH="{msys_script_path}"
elif echo "$UNAME_OUT" | grep -qi "linux" && [ -d "/mnt" ]; then
    REPO_PATH="{wsl_git_root}"
    SRC_PATH="{wsl_src_path}"
    HOOK_ORIGINAL_PATH="{wsl_original_hook}"
    PYTHON_SCRIPT_PATH="{wsl_script_path}"
else
    REPO_PATH="{posix_git_root}"
    SRC_PATH="{posix_src_path}"
    HOOK_ORIGINAL_PATH="{posix_original_hook}"
    PYTHON_SCRIPT_PATH="{posix_script_path}"
fi

# CODEMAP自動更新の実行
cd "$REPO_PATH"
export PYTHONPATH="$SRC_PATH:$PYTHONPATH"
$PYTHON_CMD "$PYTHON_SCRIPT_PATH"

# 元のpost-commitフックが存在する場合は実行
if [ -f "$HOOK_ORIGINAL_PATH" ]; then
    bash "$HOOK_ORIGINAL_PATH" "$@"
fi
"""

        # 既存のフックをバックアップ
        if hook_file.exists():
            backup_file = hooks_dir / "post-commit.original"
            if not backup_file.exists():
                shutil.copy2(hook_file, backup_file)

        # 新しいフックを書き込み
        hook_file.write_text(hook_content, encoding="utf-8", newline="\n")
        hook_file.chmod(0o755)  # 実行権限を付与

        console.print(f"[green]✅ CODEMAP post-commit hook installed: {hook_file}[/green]")
        return True

    except Exception as e:
        console.print(f"[red]❌ Failed to install CODEMAP post-commit hook: {e}[/red]")
        return False


if __name__ == "__main__":
    sys.exit(main())
