"""GitHub Action workflow generator (Pro+ tier).

Generates a CI/CD workflow with tier-conditional steps and SHA-pinned actions.
"""

from __future__ import annotations

from datetime import UTC, datetime
from pathlib import Path

import yaml

from complyform import __version__
from complyform.core.errors import ComplyFormError
from complyform.core.generators.base import GenerationResult, PolicyGenerator

# SHA pins loaded from action_pins.yaml or defaults
_DEFAULT_PINS: dict[str, str] = {
    "actions/checkout": "b4ffde65f46336ab88eb53be808477a3936bae11",
    "actions/upload-artifact": "5d5d22a31266ced268874388b861e4b58bb5c2f3",
    "bridgecrewio/checkov-action": "a0a3a82b431c4e55e8e5c02e6979fc1fb8bc2cbb",
    "open-policy-agent/conftest-action": "dd38baffc7d23f2c92a7bbf8e4db1ed681ec0929",
    "peter-evans/create-or-update-comment": "71345be0265236311c031f5c7866368bd1eff043",
}

_WORKFLOW_TEMPLATE = """\
# Auto-generated by ComplyForm v{version}
# Generated: {timestamp}
# Cloud: {cloud}
# Tier: {tier}

name: ComplyForm Compliance Check

on:
  pull_request:
    paths:
      - "**/*.tf"
      - "**/*.tfvars"
  push:
    branches: [main]
  schedule:
    - cron: "0 9 * * 1"
  workflow_dispatch:

permissions:
  contents: read
  pull-requests: write
  id-token: write

jobs:
  compliance:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: {checkout_pin}

      - name: Install ComplyForm
        run: |
          pip install complyform
          complyform --version

      - name: ComplyForm Scan + Assess
        run: |
          complyform scan --state=./terraform.tfstate --assess
        env:
          COMPLYFORM_LICENSE_KEY: ${{{{ secrets.COMPLYFORM_LICENSE_KEY }}}}
{checkov_step}
{opa_step}
      - name: Upload Artifacts
        if: always()
        uses: {upload_artifact_pin}
        with:
          name: complyform-results
          path: |
            ./policies/
            ./exports/
{dashboard_step}
{pr_comment_step}
"""

_CHECKOV_STEP = """\
      - name: Run Custom Checkov Policies
        uses: {checkov_pin}
        with:
          directory: .
          external_checks_dir: ./policies/checkov/
          soft_fail: true
"""

_OPA_STEP = """\
      - name: OPA/Conftest Evaluation
        uses: {conftest_pin}
        with:
          policy: ./policies/opa/
          file: tfplan.json
"""

_DASHBOARD_STEP = """\
      - name: Push to Dashboard
        if: github.ref == 'refs/heads/main'
        run: |
          complyform dashboard push --scan-id=latest
        env:
          COMPLYFORM_LICENSE_KEY: ${{{{ secrets.COMPLYFORM_LICENSE_KEY }}}}
"""

_PR_COMMENT_STEP = """\
      - name: PR Comment with Score
        if: github.event_name == 'pull_request'
        uses: {comment_pin}
        with:
          issue-number: ${{{{ github.event.pull_request.number }}}}
          body: |
            ## ComplyForm Compliance Score
            See artifacts for details.
"""

_README_TEMPLATE = """\
# ComplyForm CI/CD Integration

Auto-generated by ComplyForm v{version}.

## Setup

1. Add `COMPLYFORM_LICENSE_KEY` to your repository secrets.
2. Commit the workflow file:
   ```bash
   git add .github/workflows/complyform-compliance.yaml
   git push
   ```

## Configuration

- **Cloud:** {cloud}
- **Tier:** {tier}
- **Generated:** {timestamp}

## What This Does

- Scans Terraform files on every PR and push to main
- Runs compliance assessment against configured frameworks
- Uploads results as artifacts
- Comments on PRs with compliance score

## Weekly Schedule

Runs every Monday at 9:00 AM UTC.
"""


class GitHubActionGenerator(PolicyGenerator):
    """Generate GitHub Action workflow for compliance CI/CD."""

    FORMAT_ID = "github-action"
    TIER_FEATURE = "github_action"

    _SUPPORTED_TIERS = frozenset(
        {"pro", "team", "agency", "enterprise", "enterprise_unlimited"}
    )

    def supports_tier(self, tier: str) -> bool:
        return tier in self._SUPPORTED_TIERS

    def format_name(self) -> str:
        return "GitHub Action"

    def generate(
        self,
        findings: list[dict[str, object]],
        mappings: dict[str, object],
        cloud: str,
        tier: str,
        output_dir: Path,
    ) -> GenerationResult:
        pins = _load_action_pins()
        _validate_pins(pins)

        now = datetime.now(UTC).isoformat()

        # Resolve pins
        checkout_pin = _resolve_pin(pins, "actions/checkout")
        upload_pin = _resolve_pin(pins, "actions/upload-artifact")
        checkov_pin = _resolve_pin(pins, "bridgecrewio/checkov-action")
        conftest_pin = _resolve_pin(pins, "open-policy-agent/conftest-action")
        comment_pin = _resolve_pin(pins, "peter-evans/create-or-update-comment")

        # Tier-conditional steps
        checkov_step = _CHECKOV_STEP.format(checkov_pin=checkov_pin)

        opa_step = ""
        if tier in ("team", "agency", "enterprise", "enterprise_unlimited"):
            opa_step = _OPA_STEP.format(conftest_pin=conftest_pin)

        dashboard_step = ""
        if tier in ("team", "agency", "enterprise", "enterprise_unlimited"):
            dashboard_step = _DASHBOARD_STEP

        pr_comment_step = _PR_COMMENT_STEP.format(comment_pin=comment_pin)

        workflow_content = _WORKFLOW_TEMPLATE.format(
            version=__version__,
            timestamp=now,
            cloud=cloud,
            tier=tier,
            checkout_pin=checkout_pin,
            upload_artifact_pin=upload_pin,
            checkov_step=checkov_step,
            opa_step=opa_step,
            dashboard_step=dashboard_step,
            pr_comment_step=pr_comment_step,
        )

        # Write workflow
        workflow_dir = output_dir / ".github" / "workflows"
        workflow_dir.mkdir(parents=True, exist_ok=True)
        workflow_path = workflow_dir / "complyform-compliance.yaml"
        workflow_path.write_text(workflow_content, encoding="utf-8")

        # Write README
        readme_content = _README_TEMPLATE.format(
            version=__version__,
            cloud=cloud,
            tier=tier,
            timestamp=now,
        )
        readme_path = output_dir / "README-complyform-ci.md"
        readme_path.write_text(readme_content, encoding="utf-8")

        return GenerationResult(
            format=self.FORMAT_ID,
            files_written=[workflow_path, readme_path],
            artifact_count=1,
            output_dir=output_dir,
        )


def _resolve_pin(pins: dict[str, str], action: str) -> str:
    """Resolve an action to its SHA-pinned reference."""
    sha = pins.get(action, _DEFAULT_PINS[action])
    return f"{action}@{sha}"


def _load_action_pins() -> dict[str, str]:
    """Load SHA pins from action_pins.yaml if available."""
    pins_path = (
        Path(__file__).resolve().parents[3]
        / "templates"
        / "policy_gen"
        / "action_pins.yaml"
    )
    if not pins_path.exists():
        return dict(_DEFAULT_PINS)
    raw = yaml.safe_load(pins_path.read_text(encoding="utf-8"))
    if not isinstance(raw, dict):
        return dict(_DEFAULT_PINS)
    result: dict[str, str] = {}
    for key, val in raw.items():
        if isinstance(val, dict):
            result[key] = str(val.get("sha", ""))
        else:
            result[key] = str(val)
    return result


def _validate_pins(pins: dict[str, str]) -> None:
    """Reject '<sha>' as an invalid placeholder value."""
    for action, sha in pins.items():
        if sha == "<sha>":
            raise ComplyFormError(
                title="Invalid Action Pin",
                message=f"Action '{action}' has placeholder SHA '<sha>'.",
                fix=(
                    "Replace '<sha>' in templates/policy_gen/action_pins.yaml"
                    " with actual commit SHAs before generating workflows."
                ),
                error_code=83,
            )
