# Copyright (C) 2026 GoodData Corporation

"""Template rendering and file-write helpers for repo onboarding."""

from __future__ import annotations

from datetime import datetime
from pathlib import Path

from aida_mcp.server.repo_onboarding_history import TemplateHints


def now_stamp() -> str:
    return datetime.now().strftime("%Y%m%d-%H%M%S")


def _read_template_text(filename: str) -> str:
    try:
        from importlib.resources import files

        return files("aida_mcp.onboarding_templates").joinpath(filename).read_text(encoding="utf-8")
    except Exception as exc:
        return (
            f"# AIDA onboarding template missing\n\nFailed to load aida_mcp.onboarding_templates:{filename} ({exc})\n"
        )


def render_cursor_rule() -> str:
    header = "---\ndescription: MCP-powered development workflow (AIDA)\nalwaysApply: true\n---\n\n"
    body = _read_template_text("workflow_body.md")
    return header + body


def render_claude_rule() -> str:
    header = "---\napply: always\n---\n\n"
    body = _read_template_text("workflow_body.md")
    return header + body


def render_agents_rule() -> str:
    return _read_template_text("workflow_body.md")


def render_jetbrains_ai_rule() -> str:
    return _read_template_text("workflow_body.md")


def render_junie_guidelines() -> str:
    return _read_template_text("workflow_body.md")


def write_text_if_missing(path: Path, content: str, *, force: bool) -> bool:
    """Write a file if missing; if force=True, overwrite."""

    if path.exists() and not force:
        return False
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(content, encoding="utf-8")
    return True


def ensure_gitignore_contains(path: Path, entry: str) -> bool:
    """Ensure gitignore has the exact entry on a dedicated line."""

    line = entry.strip()
    if not line:
        return False
    if path.exists():
        existing_lines = path.read_text(encoding="utf-8").splitlines()
        if line in existing_lines:
            return False
        updated = existing_lines + [line]
        path.write_text("\n".join(updated).rstrip("\n") + "\n", encoding="utf-8")
        return True
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(f"{line}\n", encoding="utf-8")
    return True


def required_aida_gitignore_entries() -> tuple[str, ...]:
    return ("rules_selection.local.yaml", "git_policy.local.yaml")


def reconcile_aida_gitignore(path: Path, *, dry_run: bool) -> list[str]:
    entries = required_aida_gitignore_entries()
    existing_lines = path.read_text(encoding="utf-8").splitlines() if path.exists() else []
    missing = [entry for entry in entries if entry not in existing_lines]
    if not missing:
        return []
    if not dry_run:
        updated = [*existing_lines, *missing]
        path.parent.mkdir(parents=True, exist_ok=True)
        path.write_text("\n".join(updated).rstrip("\n") + "\n", encoding="utf-8")
    return [f".aida/.gitignore: added missing entry {entry}" for entry in missing]


def placeholder_change_domains_yaml() -> str:
    return (
        "# AIDA change domain classification\n"
        "#\n"
        "# Define how changed paths map to validation domains.\n"
        "# See `.aida/validation_policy.yaml` for mapping domains to pipelines.\n"
        "version: 1\n"
        "domains: []\n"
    )


def placeholder_validation_policy_yaml() -> str:
    return (
        "# AIDA validation policy\n"
        "#\n"
        "# This file wires domains -> pipelines -> steps (command_id + processor_id).\n"
        "# Initially empty (validate may no-op until you configure routes).\n"
        "version: 1\n"
        "validation_policy:\n"
        "  codegen: []\n"
        "  routes: []\n"
        "  pipelines: {}\n"
    )


def placeholder_validation_registry_yaml() -> str:
    return (
        "# AIDA validation registry\n"
        "#\n"
        "# Define command_id and processor_id specifications referenced by validation_policy.yaml.\n"
        "version: 1\n"
        "registry:\n"
        "  includes: []\n"
        "  commands: {}\n"
        "  processors: {}\n"
    )


def placeholder_git_policy_yaml() -> str:
    return (
        "# AIDA git policy\n"
        "#\n"
        "# Configure commit and git workflow policy used by AIDA tools.\n"
        "version: 1\n"
        "git_policy:\n"
        "  commit:\n"
        "    # Max allowed characters for the full commit subject line.\n"
        "    subject_max_chars: 70\n"
        "    # Set false to suppress ticket trailers entirely.\n"
        "    ticket_enabled: true\n"
        "    # Allowed values for the configured risk trailer.\n"
        "    risk_values: [nonprod, low, high]\n"
        "    # Set false to suppress risk trailers entirely.\n"
        "    risk_enabled: true\n"
        "    # Prefix used for optional ticket trailer placeholder `{ticket}`.\n"
        "    ticket_prefix: JIRA\n"
        "    # Prefix used for required risk trailer placeholder `{risk}`.\n"
        "    risk_prefix: risk\n"
        "    # Require `Co-authored-by:` footer in each commit.\n"
        "    require_co_authored_by: false\n"
        "    # Optional template file under .aida/ for the full commit message.\n"
        "    # Supported placeholders: {subject}, {type}, {scope}, {repository_part}, {title}, {body}, {ticket}, {ticket_values}, {risk}, {risk_value}, {co_authored_by}, {co_authored_by_values}.\n"
        "    template_file: templates/commit-message.txt\n"
        '    # If true, validate(scope="pre_commit") includes commit workflow guidance.\n'
        "    pre_commit_guidance: false\n"
        "  pr:\n"
        "    # Optional templates under .aida/ for PR title/body policy and validation.\n"
        "    # Supported placeholders include: {title}, {type}, {scope}, {repository_part}, {summary}, {test_plan}, {co_authored_by}, {ticket}, {ticket_id}, {ticket_ref_prefix}, {risk}.\n"
        "    title_template_file: templates/pr-title.txt\n"
        "    body_template_file: templates/pr-body.md\n"
        "  enforcement:\n"
        "    # off | advisory | strict (used by tooling/CI conventions).\n"
        "    mode: off\n"
        "  workflow:\n"
        "    # Prefer `git push --force-with-lease` over `--force` for unpublished branches.\n"
        "    prefer_force_with_lease: true\n"
        "    # Allow autosquash/rebase only for unpublished (not yet shared) commits.\n"
        "    autosquash_unpublished_only: true\n"
    )


def placeholder_rules_selection_yaml(*, embedded_include_paths: list[str]) -> str:
    include_lines = "\n".join([f"    - source: embedded\n      path: {path}" for path in embedded_include_paths])
    if include_lines:
        include_lines = f"\n{include_lines}"
    return (
        "# AIDA rules selection\n"
        "#\n"
        "# Shared repository defaults for selecting embedded and repo-owned rules.\n"
        "# Users can add local overrides in `.aida/rules_selection.local.yaml`.\n"
        "version: 1\n"
        "defaults:\n"
        "  embedded: core_only\n"
        "  repo: all\n"
        "include:"
        f"{include_lines}\n"
        "exclude: []\n"
        "presets: {}\n"
        "use_presets: []\n"
    )


def placeholder_commit_message_template(*, hints: TemplateHints) -> str:
    return "{type}{repository_part}: {title}\n\n{body}\n\n{co_authored_by}\n{ticket}\n{risk}\n"


def placeholder_pr_title_template(*, hints: TemplateHints) -> str:
    return "{type}{repository_part}: {title}\n"


def placeholder_pr_body_template(*, hints: TemplateHints) -> str:
    lines = [
        "# PR template generated by AIDA onboarding.",
    ]
    if hints.ticket_prefix:
        lines.append(f"# Detected ticket prefix usage in history ({hints.ticket_prefix}-123 pattern).")
    if not hints.has_history:
        lines.append("# No PR/commit history detected. Please polish this template manually.")
    lines.extend(
        [
            "",
            "## Summary",
            "- {summary}",
            "",
            "## Test plan",
            "- {test_plan}",
            "",
            "{co_authored_by}",
            "{ticket}",
            "{risk}",
        ]
    )
    return "\n".join(lines).rstrip() + "\n"
