"""CI/CD Templates Generator for mcpaudit.

Generates ready-to-use CI/CD pipeline configurations for GitHub Actions,
GitLab CI, and pre-commit hooks. Each template is configurable with
severity thresholds, trust score minimums, output formats, and scan paths.

Zero external dependencies -- pure Python stdlib.
"""

from __future__ import annotations

import json
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any


# ---------------------------------------------------------------------------
# Configuration model
# ---------------------------------------------------------------------------

@dataclass
class CITemplateOptions:
    """Configuration options for CI/CD template generation."""

    severity_threshold: str = "high"  # critical, high, medium, low
    min_trust_score: int = 70
    output_format: str = "text"  # text, json, html, sarif
    scan_paths: list[str] = field(default_factory=lambda: ["."])
    python_version: str = "3.11"
    mcpaudit_version: str = "latest"
    fail_on_findings: bool = True
    enable_sarif_upload: bool = True
    enable_supply_chain: bool = False
    enable_secrets_scan: bool = False
    extra_args: list[str] = field(default_factory=list)

    def to_dict(self) -> dict[str, Any]:
        return {
            "severity_threshold": self.severity_threshold,
            "min_trust_score": self.min_trust_score,
            "output_format": self.output_format,
            "scan_paths": self.scan_paths,
            "python_version": self.python_version,
            "mcpaudit_version": self.mcpaudit_version,
            "fail_on_findings": self.fail_on_findings,
            "enable_sarif_upload": self.enable_sarif_upload,
            "enable_supply_chain": self.enable_supply_chain,
            "enable_secrets_scan": self.enable_secrets_scan,
            "extra_args": self.extra_args,
        }


# ---------------------------------------------------------------------------
# GitHub Actions template
# ---------------------------------------------------------------------------

def generate_github_actions(
    options: CITemplateOptions | None = None,
) -> str:
    """Generate GitHub Actions workflow YAML for mcpaudit.

    Args:
        options: Template configuration options.

    Returns:
        YAML string for .github/workflows/mcpaudit.yml
    """
    opts = options or CITemplateOptions()
    targets = " ".join(opts.scan_paths)
    pip_ver = "" if opts.mcpaudit_version == "latest" else f"=={opts.mcpaudit_version}"

    format_flag = ""
    if opts.output_format != "text":
        format_flag = f"\n          --format {opts.output_format}"

    extra = ""
    if opts.extra_args:
        extra = "\n          " + " ".join(opts.extra_args)

    supply_chain_step = ""
    if opts.enable_supply_chain:
        supply_chain_step = f"""
      - name: Supply Chain Scan
        run: mcpaudit supply-chain {targets}
        continue-on-error: true
"""

    secrets_step = ""
    if opts.enable_secrets_scan:
        secrets_step = f"""
      - name: Secret Scan
        run: mcpaudit secrets {targets}
        continue-on-error: true
"""

    sarif_steps = ""
    if opts.enable_sarif_upload:
        sarif_steps = f"""
      - name: Generate SARIF
        if: always()
        run: mcpaudit {targets} --format sarif --output results.sarif || true

      - name: Upload SARIF to GitHub Security
        if: always()
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: results.sarif
        continue-on-error: true
"""

    return f"""name: MCP Security Audit

on:
  push:
    branches: [main, master]
  pull_request:
    branches: [main, master]

permissions:
  contents: read
  security-events: write

jobs:
  mcpaudit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python {opts.python_version}
        uses: actions/setup-python@v5
        with:
          python-version: "{opts.python_version}"

      - name: Install mcpaudit
        run: pip install mcpaudit{pip_ver}

      - name: Run MCP Security Scan
        run: >
          mcpaudit {targets}
          --severity {opts.severity_threshold}
          --min-score {opts.min_trust_score}{format_flag}{extra}
{supply_chain_step}{secrets_step}{sarif_steps}"""


# ---------------------------------------------------------------------------
# GitLab CI template
# ---------------------------------------------------------------------------

def generate_gitlab_ci(
    options: CITemplateOptions | None = None,
) -> str:
    """Generate GitLab CI job YAML for mcpaudit.

    Args:
        options: Template configuration options.

    Returns:
        YAML string for .gitlab-ci.yml inclusion.
    """
    opts = options or CITemplateOptions()
    targets = " ".join(opts.scan_paths)
    pip_ver = "" if opts.mcpaudit_version == "latest" else f"=={opts.mcpaudit_version}"

    format_flag = ""
    if opts.output_format != "text":
        format_flag = f" --format {opts.output_format}"

    extra = ""
    if opts.extra_args:
        extra = " " + " ".join(opts.extra_args)

    supply_chain_line = ""
    if opts.enable_supply_chain:
        supply_chain_line = f"\n    - mcpaudit supply-chain {targets} || true"

    secrets_line = ""
    if opts.enable_secrets_scan:
        secrets_line = f"\n    - mcpaudit secrets {targets} || true"

    allow_failure = "false" if opts.fail_on_findings else "true"

    return f"""mcpaudit:
  stage: test
  image: python:{opts.python_version}-slim
  before_script:
    - pip install --quiet mcpaudit{pip_ver}
  script:
    - >
      mcpaudit {targets}
      --severity {opts.severity_threshold}
      --min-score {opts.min_trust_score}{format_flag}{extra}{supply_chain_line}{secrets_line}
  artifacts:
    when: always
    paths:
      - mcpaudit-report.*
    reports:
      sast: mcpaudit-report.json
  allow_failure: {allow_failure}
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
"""


# ---------------------------------------------------------------------------
# Pre-commit template
# ---------------------------------------------------------------------------

def generate_pre_commit(
    options: CITemplateOptions | None = None,
) -> str:
    """Generate pre-commit hook configuration for mcpaudit.

    Args:
        options: Template configuration options.

    Returns:
        YAML string for .pre-commit-config.yaml inclusion.
    """
    opts = options or CITemplateOptions()

    args_list: list[str] = [
        f"--severity {opts.severity_threshold}",
        f"--min-score {opts.min_trust_score}",
    ]
    if opts.output_format != "text":
        args_list.append(f"--format {opts.output_format}")
    if opts.extra_args:
        args_list.extend(opts.extra_args)

    args_yaml = "\n".join(f"      - {a}" for a in args_list)

    rev = "latest"
    if opts.mcpaudit_version != "latest":
        rev = f"v{opts.mcpaudit_version}"

    return f"""repos:
  - repo: https://github.com/anthropics/mcpaudit
    rev: {rev}
    hooks:
      - id: mcpaudit
        name: MCP Security Audit
        entry: mcpaudit
        language: python
        types_or: [python, ts, javascript]
        args:
{args_yaml}
        pass_filenames: true
"""


# ---------------------------------------------------------------------------
# Dispatch / convenience
# ---------------------------------------------------------------------------

SUPPORTED_PLATFORMS: tuple[str, ...] = ("github", "gitlab", "pre-commit")


def generate_ci_template(
    platform: str,
    options: CITemplateOptions | None = None,
) -> str:
    """Generate CI template for a platform.

    Args:
        platform: One of 'github', 'gitlab', 'pre-commit'.
        options: Template configuration options.

    Returns:
        Configuration string.

    Raises:
        ValueError: If platform is not supported.
    """
    generators = {
        "github": generate_github_actions,
        "gitlab": generate_gitlab_ci,
        "pre-commit": generate_pre_commit,
    }
    if platform not in generators:
        valid = ", ".join(sorted(generators.keys()))
        raise ValueError(f"Unknown platform '{platform}'. Valid: {valid}")
    return generators[platform](options)


def get_default_output_filename(platform: str) -> str:
    """Return suggested output filename for a platform.

    Args:
        platform: CI platform name.

    Returns:
        Suggested filename string.
    """
    filenames = {
        "github": ".github/workflows/mcpaudit.yml",
        "gitlab": ".gitlab-ci.yml",
        "pre-commit": ".pre-commit-config.yaml",
    }
    return filenames.get(platform, f"mcpaudit-{platform}.yml")


def format_ci_template_json(
    platform: str,
    options: CITemplateOptions | None = None,
) -> str:
    """Generate CI template and return as JSON metadata.

    Args:
        platform: CI platform name.
        options: Template configuration options.

    Returns:
        JSON string with template content and metadata.
    """
    opts = options or CITemplateOptions()
    content = generate_ci_template(platform, opts)
    data = {
        "platform": platform,
        "filename": get_default_output_filename(platform),
        "options": opts.to_dict(),
        "content": content,
    }
    return json.dumps(data, indent=2, ensure_ascii=False)
