"""Phase 2b — inject Gitea Actions workflows (PR gates) into the recruiter package.

- sanitize.yml: fails on PII, e-mail addresses, secrets, internal URLs
- eval.yml: validates package structure & required files

Both run on the self-hosted act_runner (host mode, label "windows").
Idempotent: files are simply (re)written.
"""
import os

SKILLS_DIR = os.path.join(os.path.dirname(__file__), "..", "skills")

SANITIZE = r'''name: sanitize
# PR gate: block personal data, secrets and tenant-internal references from
# entering the shared skill library. Every layer boundary is a gate.
# Deliberately PR-only: INSIDE a private tenant repo internal details are
# legitimate; the gate guards the boundary to the shared layers.
on:
  pull_request:

jobs:
  pii-scan:
    runs-on: windows
    steps:
      - uses: actions/checkout@v4
      - name: Scan for PII / secrets / internal URLs
        shell: python
        run: |
          import os, re, sys

          RULES = [
              ("e-mail address", re.compile(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}")),
              ("phone number", re.compile(r"(?<![\w/.-])\+?\d[\d ()\-]{8,}\d(?![\w/])")),
              ("secret assignment", re.compile(r"(?i)(password|passwd|secret|api[_-]?key|token)\s*[:=]\s*['\"]?[A-Za-z0-9_\-]{6,}")),
              ("internal URL/host", re.compile(r"(?i)(\bintranet\b|\.internal\b|\.local\b|\.corp\b|\b10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b|\b192\.168\.\d{1,3}\.\d{1,3}\b)")),
              ("person name marker", re.compile(r"(?i)\b(hiring manager|contact):\s*[A-Z][a-z]+ [A-Z][a-z]+")),
          ]
          ALLOW = re.compile(r"(?i)(esco\.ec\.europa\.eu|onetcenter\.org|data\.europa\.eu|creativecommons\.org)")

          findings = []
          for root, dirs, files in os.walk("."):
              dirs[:] = [d for d in dirs if d not in (".git", ".gitea")]
              for name in files:
                  path = os.path.join(root, name)
                  try:
                      text = open(path, encoding="utf-8", errors="ignore").read()
                  except OSError:
                      continue
                  for lineno, line in enumerate(text.splitlines(), 1):
                      if ALLOW.search(line):
                          continue
                      for label, rx in RULES:
                          m = rx.search(line)
                          if not m:
                              continue
                          # ISO-Datumsangaben (2026-07-06) sind keine Telefonnummern
                          if label == "phone number" and re.fullmatch(r"\d{4}-\d{2}-\d{2}", m.group(0)):
                              continue
                          findings.append(f"{path}:{lineno}: {label}: {line.strip()[:120]}")

          if findings:
              print("SANITIZE GATE FAILED — remove/anonymize before publishing:")
              print("\n".join(findings))
              sys.exit(1)
          print("sanitize: clean — no PII, secrets or internal references found.")
'''

EVAL = r'''name: eval
# Structural eval: a skill package must be complete and within limits before
# it can be merged. Complements sanitize.yml (content gate).
on:
  pull_request:
  push:
    branches: [main]

jobs:
  structure:
    runs-on: windows
    steps:
      - uses: actions/checkout@v4
      - name: Validate package structure
        shell: python
        run: |
          import json, os, sys

          errors = []
          REQUIRED = [
              "SKILL.md",
              "manifest.json",
              "references/profile.md",
              "references/tasks.md",
              "references/skills.md",
              "references/tools.md",
          ]
          for f in REQUIRED:
              if not os.path.isfile(f):
                  errors.append(f"missing required file: {f}")

          if os.path.isfile("SKILL.md"):
              lines = open("SKILL.md", encoding="utf-8").read().splitlines()
              if len(lines) > 300:
                  errors.append(f"SKILL.md too long: {len(lines)} lines (max 300)")
              if not lines or lines[0].strip() != "---":
                  errors.append("SKILL.md missing frontmatter")

          if os.path.isfile("manifest.json"):
              m = json.load(open("manifest.json", encoding="utf-8"))
              for key in ("name", "version", "layer", "ids", "sources", "attribution"):
                  if key not in m:
                      errors.append(f"manifest.json missing key: {key}")

          if errors:
              print("EVAL FAILED:")
              print("\n".join(f"- {e}" for e in errors))
              sys.exit(1)
          print("eval: package structure OK.")
'''


def main():
    recruiter = next((d for d in sorted(os.listdir(SKILLS_DIR))
                      if "recruit" in d and os.path.isdir(os.path.join(SKILLS_DIR, d))), None)
    if not recruiter:
        print("SKIP: no recruiter package found yet (run p2 first)")
        return
    wf = os.path.join(SKILLS_DIR, recruiter, ".gitea", "workflows")
    os.makedirs(wf, exist_ok=True)
    open(os.path.join(wf, "sanitize.yml"), "w", encoding="utf-8", newline="\n").write(SANITIZE)
    open(os.path.join(wf, "eval.yml"), "w", encoding="utf-8", newline="\n").write(EVAL)
    print(f"workflows injected into skills/{recruiter}/.gitea/workflows/")


if __name__ == "__main__":
    main()
