"""
Constants and configuration for the sync tool.
"""

from enum import Enum
from typing import Any, Final, Literal


class FileCategory(Enum):
    """Categories for file sync handling."""

    SYNC_ALWAYS = "sync"  # Commands, hooks, prompts, scripts - overwrite
    MERGE_SMART = "merge"  # settings.json - intelligent JSON merge
    MERGE_YAML = "merge_yaml"  # Workflow YAML - intelligent YAML merge (future use)
    SKIP_ALWAYS = "skip"  # settings.local.json, state/, logs/ - never sync
    COPY_IF_MISSING = "copy_once"  # README.md - don't overwrite

    def can_symlink(self) -> bool:
        """Check if this category can be symlinked in editable mode."""
        # Only SYNC_ALWAYS files can be symlinked
        # Never symlink settings (needs merging) or copy-if-missing files (project-specific)
        return self == FileCategory.SYNC_ALWAYS


# File patterns and their sync categories
# NOTE: Patterns are now root-relative (explicit .claude/ prefix for .claude/ files)
# Rules can be either:
# 1. FileCategory directly (destination = source path)
# 2. Dict with 'category' and optional 'destination'/'exclude' keys
#    - destination is relative to project root
#    - destination can be outside .claude/ (e.g., .git/hooks/, .github/workflows/)
FILE_RULES: Final[dict[str, FileCategory | dict[str, Any]]] = {
    # .claude/ directory files (all patterns now explicit with .claude/ prefix)
    ".claude/commands/*.md": FileCategory.SYNC_ALWAYS,
    ".claude/hooks/*.sh": FileCategory.SYNC_ALWAYS,
    # Git hooks with destination mapping - sync to .git/hooks/ instead of .claude/git-hooks/
    # Exclude documentation files (*.md) from this mapping
    ".claude/git-hooks/*": {
        "category": FileCategory.SYNC_ALWAYS,
        "destination": ".git/hooks/{filename}",
        "exclude": ["*.md", "README*"],
    },
    ".claude/prompts/*.md": FileCategory.SYNC_ALWAYS,
    ".claude/scripts/*.sh": FileCategory.SYNC_ALWAYS,
    ".claude/scripts/*.py": FileCategory.SYNC_ALWAYS,
    # Script dependencies must sync with scripts
    ".claude/scripts/requirements.txt": FileCategory.SYNC_ALWAYS,
    ".claude/settings.json": FileCategory.MERGE_SMART,
    ".claude/settings.local.json": FileCategory.SKIP_ALWAYS,
    ".claude/state/*": FileCategory.SKIP_ALWAYS,
    ".claude/logs/*": FileCategory.SKIP_ALWAYS,
    # Nested .gitignore files for runtime directories
    # MANAGED FILES - These are auto-synced and should not be customized in target projects
    # NOTE: We use nested .gitignore files instead of root patterns because
    # patterns like `.claude/state/` in root .gitignore don't reliably match
    # files like `.claude/state/*.json` across all git versions/platforms.
    # The nested approach (.gitignore with `*` and `!.gitignore`) is more robust.
    ".claude/state/.gitignore": FileCategory.SYNC_ALWAYS,
    ".claude/logs/.gitignore": FileCategory.SYNC_ALWAYS,
    ".claude/.backup/.gitignore": FileCategory.SYNC_ALWAYS,
    ".claude/README.md": FileCategory.COPY_IF_MISSING,
    ".claude/CLAUDE.md": FileCategory.COPY_IF_MISSING,  # Don't overwrite project-specific
    ".claude/standards/*.md": FileCategory.SYNC_ALWAYS,  # AI-optimized engineering standards
    ".claude/context/*": FileCategory.SYNC_ALWAYS,
    ".claude/knowledge/**/*": FileCategory.SYNC_ALWAYS,  # Recursive pattern (includes pr-feedback/)
    ".claude/integrations/*": FileCategory.SYNC_ALWAYS,
    ".claude/metrics/*": FileCategory.SYNC_ALWAYS,
    # Root-level files with destination mapping
    #
    # Workflow YAML files: COPY_IF_MISSING allows target projects to customize workflows
    ".github/workflows/*.yml": {
        "category": FileCategory.COPY_IF_MISSING,
        "destination": ".github/workflows/{filename}",
    },
    # Requirements files: SYNC_ALWAYS ensures dependency versions stay synchronized
    # Rationale: Workflows reference specific tool versions (e.g., ruff, mypy, pytest)
    # If requirements diverge from workflow expectations, CI will break
    # Target projects should not customize these - they track template versions
    ".github/workflows/*.txt": {
        "category": FileCategory.SYNC_ALWAYS,
        "destination": ".github/workflows/{filename}",
    },
    # GitHub templates: COPY_IF_MISSING allows customization while providing standards
    ".github/PULL_REQUEST_TEMPLATE.md": {
        "category": FileCategory.COPY_IF_MISSING,
        "destination": ".github/PULL_REQUEST_TEMPLATE.md",
    },
    ".github/SECURITY.md": {
        "category": FileCategory.COPY_IF_MISSING,
        "destination": ".github/SECURITY.md",
    },
    ".github/ISSUE_TEMPLATE/*.yml": {
        "category": FileCategory.COPY_IF_MISSING,
        "destination": ".github/ISSUE_TEMPLATE/{filename}",
    },
    # Environment setup example - already has .example suffix
    ".envrc.example": {
        "category": FileCategory.COPY_IF_MISSING,
        "destination": ".envrc.example",
    },
    # Development tooling: lefthook, bandit
    # COPY_IF_MISSING allows projects to customize these files
    #
    # NOTE: Justfile is NOT synced because it's almost always super custom per project.
    # Instead, we provide Justfile.example as a template that projects can copy.
    "Justfile.example": {
        "category": FileCategory.COPY_IF_MISSING,
        "destination": "Justfile.example",
    },
    "lefthook.yml": {
        "category": FileCategory.COPY_IF_MISSING,
        "destination": "lefthook.yml",
    },
    ".bandit": {
        "category": FileCategory.COPY_IF_MISSING,
        "destination": ".bandit",
    },
}

# Patterns to skip during sync
# NOTE: Two-layer skip strategy:
# 1. Git-aware skipping (automatic via is_git_ignored() in file_ops.py)
#    - Skips .pytest_cache/*, __pycache__/*, *.pyc, build/, dist/, etc.
# 2. Explicit SKIP_PATTERNS (for tracked files that shouldn't sync)
SKIP_PATTERNS: Final[list[str]] = [
    # Git directory (never sync)
    ".git/*",
    # Sync tool internals
    ".claude/.backup/*",
    ".claude/state/*",  # Runtime state (also gitignored)
    ".claude/logs/*",  # Debug logs (also gitignored)
    ".claude/settings.local.json",  # Personal overrides (also gitignored)
    ".claude/.shadow",  # Shadow mode marker (local only)
    # Sync tool package (pip-installable persuade package)
    "persuade/*",  # persuade package directory (top-level)
    "persuade/**/*",  # persuade package directory (nested)
    # Test directory for persuade package
    "tests/*",  # persuade package tests (top-level)
    "tests/**/*",  # persuade package tests (nested)
    # Root-level project-specific files (tracked but shouldn't sync)
    "README.md",  # This repo's README
    "LICENSE",  # This repo's license
    "docs/*",  # This repo's documentation (top-level files)
    "docs/**/*",  # This repo's documentation (subdirectories)
    "tips-and-tricks/*",  # This repo's tips (top-level files)
    "tips-and-tricks/**/*",  # This repo's tips (subdirectories)
    "pyproject.toml",  # This repo's Python config
    ".gitignore",  # Project-specific ignores
    "test-projects/*",  # Test projects (top-level)
    "test-projects/**/*",  # Test projects (nested)
]

# Directories to create in target if missing
REQUIRED_DIRECTORIES: Final[list[str]] = [
    "commands",
    "hooks",
    "git-hooks",  # Git hooks (pre-push, etc.) - installed to .git/hooks/
    "scripts",
    "prompts",
    "standards",  # AI-optimized engineering standards
    "context",
    "knowledge",
    "knowledge/pr-feedback",  # Feedback classification guidelines (merged from guidelines/)
    "integrations",
    "metrics",
    "state",  # Required local runtime state directory (not synced)
    "logs",  # Required local debug logs directory (not synced)
    ".backup",  # Required local sync tool backup directory (not synced)
]

# Files that must be executable (root-relative patterns)
EXECUTABLE_PATTERNS: Final[list[str]] = [
    ".claude/hooks/*.sh",
    ".claude/git-hooks/*",  # Git hooks don't need .sh extension
    ".git/hooks/*",  # Git hooks synced to destination
    ".claude/scripts/*.sh",
]

# Git command timeouts (in seconds)
# Single file check - 5s sufficient for most repos
GIT_CHECK_IGNORE_TIMEOUT: Final[int] = 5
# Pattern matching may scan many files - allow 10s
GIT_LS_FILES_TIMEOUT: Final[int] = 10
# Git repository root lookup - quick command, 5s timeout
GIT_REV_PARSE_TIMEOUT: Final[int] = 5

# System dependencies required
REQUIRED_DEPENDENCIES: Final[list[str]] = ["jq", "gh", "bash"]
OPTIONAL_DEPENDENCIES: Final[list[str]] = ["claude"]

# Gitignore entries required for Claude Code
REQUIRED_GITIGNORE_ENTRIES: Final[list[str]] = [
    ".claude/settings.local.json",
    ".claude/state/",
    ".claude/logs/",
    ".claude/.backup/",
]

# Explanations for why each gitignore entry is required
GITIGNORE_EXPLANATIONS: Final[dict[str, str]] = {
    ".claude/settings.local.json": "personal overrides - never commit",
    ".claude/state/": "runtime state - ephemeral",
    ".claude/logs/": "debug logs - local only",
    ".claude/.backup/": "sync tool backups - local only",
}

# Mode marker values
EDITABLE_MODE_MARKER: Final[Literal["editable"]] = "editable"

# Special paths that require specific handling
GITHUB_WORKFLOWS_PATH: Final[str] = ".github/workflows/"

# Windows path length limit (in characters)
# Windows has a historical 260-character MAX_PATH limit unless long path support is enabled
# Reference: https://learn.microsoft.com/windows/win32/fileio/maximum-file-path-limitation
WINDOWS_MAX_PATH_LENGTH: Final[int] = 260
