[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "bengal"
version = "0.2.3"
description = "A high-performance static site generator with modular architecture"
readme = "README.md"
requires-python = ">=3.14"
license = "MIT"
authors = [{ name = "Bengal Contributors", email = "lbeezr@icloud.com" }]
keywords = [
    "static-site-generator",
    "ssg",
    "documentation",
    "markdown",
    "website",
    "free-threading",
    "performance",
]
classifiers = [
    "Development Status :: 3 - Alpha",
    "Intended Audience :: Developers",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.14",
    "Topic :: Documentation",
    "Topic :: Software Development :: Documentation",
]
dependencies = [
    "click>=8.1.7",

    "jinja2>=3.1.0",
    "rosettes>=0.2.0",
    "kida-templates>=0.2.2",                   # Kida template engine (AST-native, free-threading ready)
    "patitas>=0.3.1",                          # Markdown + notebook parser (CommonMark, .ipynb)
    "pyyaml>=6.0",
    "python-frontmatter>=1.0.0",
    "jsmin>=3.0.1",
    "pillow>=10.0.0",                          # Image processing for social cards
    "psutil>=5.9.0",                           # For better process management in cleanup
    "textual>=0.96",                           # Interactive dashboards (Visual API requires >=0.96)
    "textual-serve>=0.1.0",                    # Web-based dashboard access
    "questionary>=2.0.0",                      # Interactive CLI prompts with arrow key navigation
    "watchfiles>=0.20",                        # Rust-based file watching for dev server (fast)
    "bengal-pounce>=0.2.0",                    # ASGI server for dev server (replaces ThreadingTCPServer)
    "httpx>=0.27.0",                           # Async HTTP client for link checking
    "uvloop>=0.21.0; sys_platform != 'win32'", # Rust-based event loop (Linux/macOS)
    "packaging>=23.0",                         # Version parsing for upgrade checks
]

[project.optional-dependencies]
# Pre-built Lunr search index (faster client-side search)
search = ["lunr>=0.7.0"]


# Image processing (RFC: hugo-inspired-features)
# Note: Pillow is already a core dependency for social cards
# These extras add advanced image processing features
images = ["Pillow>=10.0"] # Already included, explicit for clarity
smartcrop = [
    "Pillow>=10.0",
    "smartcrop>=0.3",
] # Smart face/feature detection cropping
avif = ["Pillow>=10.0", "pillow-avif-plugin>=1.3"] # AVIF format output support
fast-images = ["pyvips>=2.2"] # libvips acceleration (advanced users)

# Content Layer - Remote content sources
# These provide async HTTP for fetching from GitHub, REST APIs, Notion, etc.
github = ["aiohttp>=3.9.0"]
notion = ["aiohttp>=3.9.0", "cachetools>=5.0.0"]      # cachetools for block caching
rest = ["aiohttp>=3.9.0"]
all-sources = ["aiohttp>=3.9.0", "cachetools>=5.0.0"] # All remote sources

# Note: Dev dependencies use [dependency-groups] (PEP 735) - install with: uv sync --group dev

[project.scripts]
bengal = "bengal.__main__:run"

[project.urls]
Homepage = "https://github.com/lbliii/bengal"
Documentation = "https://github.com/lbliii/bengal"
Repository = "https://github.com/lbliii/bengal"
"Bug Tracker" = "https://github.com/lbliii/bengal/issues"

[tool.setuptools.packages.find]
where = ["."]
include = ["bengal*"]

[tool.setuptools.package-data]
bengal = [
    "themes/**/*",
    "assets/**/*",
    "analysis/graph/templates/**/*",
    "scaffolds/**/*",
    "py.typed",
]

[tool.ruff]
line-length = 100
target-version = "py314"

[tool.ruff.lint]
# Enable Python upgrade rules and other quality checks
select = [
    "E",    # pycodestyle errors
    "W",    # pycodestyle warnings
    "F",    # pyflakes (unused imports, variables, etc.)
    "UP",   # pyupgrade - Python modernization
    "B",    # flake8-bugbear - common bugs
    "SIM",  # flake8-simplify - simplify code
    "I",    # isort - import sorting
    "PIE",  # misc lints (unnecessary pass, duplicate dict keys, etc.)
    "PERF", # perflint - performance anti-patterns
    "C4",   # unnecessary comprehensions/list()/dict() calls
    "RUF",  # Ruff-specific (unused noqa, mutable class defaults, etc.)
    "PT",   # flake8-pytest-style - pytest best practices
]
ignore = [
    "E501",   # line too long - handled by formatter, manual review for long strings
    "RUF001", # ambiguous unicode in string (intentional × symbols, em-dashes)
    "RUF002", # ambiguous unicode in docstring (intentional typography)
    "RUF003", # ambiguous unicode in comment (intentional typography)
]

# Per-file ignore rules
[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401"]   # Allow unused imports in __init__ files
"tests/**/*.py" = ["S101"] # Allow assert in tests
# Jinja test functions use test_ prefix by convention (not pytest tests)
"bengal/rendering/template_tests.py" = ["PT028"]
# LRUCache.keys() returns list[K], not a dict - SIM118 false positive
"bengal/rendering/template_functions/navigation/scaffold.py" = ["SIM118"]
# PT017: These tests verify "either success or graceful failure" pattern
# PT012/SIM117: Context manager exception tests use nested structure intentionally
"tests/integration/test_error_recovery.py" = ["PT017"]
"tests/integration/test_config_system_integration.py" = ["PT017"]
"tests/integration/warm_build/test_data_files.py" = ["PT017"]
"tests/unit/rendering/test_asset_manifest_contextvar.py" = ["PT012", "SIM117"]
"tests/unit/rendering/parsers/test_patitas/test_contextvar_config.py" = [
    "PT012",
    "SIM117",
]
# Hypothesis @given injects parameter - pytest PT019 false positive
"tests/unit/utils/test_dates_properties.py" = ["PT019"]

[tool.ty.environment]
python-version = "3.14"

[tool.ty.src]
exclude = ["tests/roots/", "MagicMock/", "dist/", "build/"]

[tool.ty.rules]
# Relax rules that produce too many false positives or are overly strict
# These are still checked but won't fail CI (warn instead of error)
unresolved-import = "warn"               # Third-party stubs often incomplete
unresolved-attribute = "warn"            # Dynamic attribute access patterns
invalid-argument-type = "warn"           # Gradual typing - allow flexibility
possibly-unresolved-reference = "ignore" # Too noisy with conditional imports

# Relax additional rules that are too strict for large codebases
call-non-callable = "warn"       # False positives with Protocol/dynamic types
invalid-return-type = "warn"     # Gradual typing flexibility
invalid-assignment = "warn"      # Allows incremental typing improvements
invalid-type-arguments = "warn"  # Generics constraints too strict
not-subscriptable = "warn"       # Protocol objects missing __getitem__
invalid-method-override = "warn" # Liskov violations - review later
unused-ignore-comment = "warn"   # Flag stale type: ignore comments for cleanup

# Relax remaining rules to unblock CI - fix incrementally
unresolved-reference = "warn"          # Missing imports - fix these properly
unknown-argument = "warn"              # Wrong kwargs - needs investigation
missing-argument = "warn"              # Missing args - needs investigation
unsupported-operator = "warn"          # Type operations - review later
not-iterable = "warn"                  # Iteration issues
too-many-positional-arguments = "warn" # Signature mismatches
no-matching-overload = "warn"          # Overload issues

[dependency-groups]
dev = [
    # Testing
    "pytest>=8.0.0",
    "pytest-cov>=4.1.0",
    "pytest-mock>=3.11.0",
    "pytest-xdist>=3.3.0",
    "pytest-timeout>=2.2.0",
    "pytest-asyncio>=0.23.0",
    "pytest-forked>=1.6.0",           # Isolated test execution for stateful tests
    "pytest-textual-snapshot>=0.4.0", # Textual dashboard snapshot testing
    "hypothesis>=6.92.0",
    # Linting & Type Checking
    "ty>=0.0.11",   # Astral type checker (Rust-based)
    "ruff>=0.15.1", # 0.15.1+ fixes except-parenthesis bug (PEP 758 + as clause)
    # Test Utilities
    "beautifulsoup4>=4.12.0", # HTML validation in integration tests
    "markdown>=3.5.0",        # Optional python-markdown parser for tests
    "tomli-w>=1.0.0",         # TOML writing (pairs with stdlib tomllib)
    # Type Stubs
    "types-pyyaml>=6.0.12",
    "types-psutil>=5.9.0",
    "types-pygments>=2.18.0",
    "types-python-dateutil>=2.9.0",
    "types-markdown>=3.5.0",
    "types-jinja2>=2.11.0",
    "pytest-benchmark>=5.2.3",
    "radon>=6.0.1",
    "prek>=0.3.2",
    "poethepoet>=0.35.0",
    "pytest-randomly>=3.15.0",
]

# =============================================================================
# Task Runner (poethepoet) - use: poe <task>
# =============================================================================
# Replaces Makefile with Python-native task definitions
# Run `poe --help` to see all available tasks

[tool.poe.tasks]
# Development Server
serve = { cmd = "bengal site serve site", help = "Start development server for site/" }
dev = { cmd = "bengal serve", help = "Start dev server (auto-detects site)" }

# Building
build = { cmd = "bengal site build site", help = "Build the documentation site" }
build-prod = { cmd = "bengal build -e production", help = "Build with production config", cwd = "site" }

# Testing
test = { cmd = "pytest", help = "Run full test suite" }
test-unit = { cmd = "pytest tests/unit/ -x -q", help = "Run unit tests only (fast)" }
test-integration = { cmd = "pytest tests/integration/ -x -q --timeout=30", help = "Run integration tests" }
test-fast = { cmd = "pytest tests/ -x -q --ignore=tests/e2e --ignore=tests/integration", help = "Fast feedback loop (unit only)" }
test-cov = { cmd = "pytest tests/ --cov=bengal --cov-report=term-missing", help = "Run tests with coverage" }
test-parallel = { cmd = "pytest tests/ -n auto -x -q", help = "Run tests in parallel (pytest-xdist)" }
test-random = { cmd = "pytest tests/ -p randomly --randomly-seed=random -x -q", help = "Run tests in random order" }
test-verbose = { cmd = "pytest tests/ -v --tb=long", help = "Run tests with verbose output" }

# Type Checking
ty = { cmd = "ty check bengal/", help = "Run ty type checker (fast, Rust-based)" }
ty-strict = { cmd = "ty check bengal/ --error-on-warning", help = "Strict type checking (warnings as errors)" }

# Linting & Formatting
lint = { cmd = "ruff check .", help = "Run ruff linter" }
lint-fix = { cmd = "ruff check . --fix", help = "Run ruff linter with auto-fix" }
format = { cmd = "ruff format .", help = "Format code with ruff" }
format-check = { cmd = "ruff format . --check", help = "Check formatting without changing files" }

# Pre-commit
hooks = { cmd = "prek run --all-files", help = "Run all pre-commit hooks" }
hooks-install = { cmd = "prek install", help = "Install pre-commit hooks" }

# CI Pipeline (what CI runs)
ci = { sequence = [
    "lint",
    "ty",
    "test",
], help = "Run full CI check (lint → type → test)" }
check = { sequence = [
    "lint",
    "format-check",
    "ty",
], help = "Quick check (lint + format + types)" }

# Build & Release
dist = { shell = "rm -rf dist/ && uv build && ls -la dist/", help = "Build distribution packages" }
publish = { cmd = "uv publish", help = "Publish to PyPI" }
release = { sequence = [
    "dist",
    "publish",
], help = "Build and publish in one step" }

# Code Quality Analysis
deadcode = { cmd = "ruff check . --select F401,F841 --statistics", help = "Find unused imports/variables" }
complexity = { cmd = "radon cc bengal/ -a -s", help = "Analyze code complexity" }

# Deploy Test (simulates GitHub Pages)
deploy-test.shell = """
cd site && bengal build -e production
echo ""
echo "Verifying CSS exists..."
ls -la public/assets/css/style.css || (echo "ERROR: CSS not found!" && exit 1)
echo ""
echo "Starting server at http://localhost:8000/bengal/"
echo "Press Ctrl+C to stop"
cd public && python3 -m http.server 8000
"""
deploy-test.help = "Build production & serve (simulates GitHub Pages)"

# Cleanup
clean.shell = """
rm -rf dist build .pytest_cache .coverage htmlcov .ruff_cache .bengal public .ty_cache
find . -type d -name '__pycache__' -exec rm -rf {} + 2>/dev/null || true
"""
clean.help = "Remove build artifacts and caches"
