#!/usr/bin/env python3
"""Generate k3s-test file reference markdown from repo tree."""
from __future__ import annotations

import os
import re
from pathlib import Path

ROOT = Path(__file__).resolve().parents[4]  # k3s-test/
OUT = Path(__file__).resolve().parent

SKIP_PARTS = {
    "node_modules", ".git", "vendor", "dist", ".vitepress/cache",
    ".vitepress/dist", ".terraform", ".tmp-chart", ".phpunit",
}
SKIP_NAMES = {".DS_Store"}


def should_skip(rel: str) -> bool:
    parts = Path(rel).parts
    if any(p in SKIP_PARTS for p in parts):
        return True
    if Path(rel).name in SKIP_NAMES:
        return True
    if "public/build" in rel:
        return True
    return False


def describe(rel: str) -> str:
    name = Path(rel).name
    p = rel.lower()

    # Extension-based defaults
    ext = Path(rel).suffix.lower()
    ext_map = {
        ".sh": "Shell-скрипт",
        ".py": "Python-скрипт",
        ".yaml": "YAML-конфиг / Helm / K8s",
        ".yml": "YAML-конфиг / docker-compose",
        ".md": "Документация Markdown",
        ".json": "JSON-данные / конфиг",
        ".sql": "SQL (schema или seed)",
        ".php": "PHP (Symfony)",
        ".twig": "Twig-шаблон",
        ".js": "JavaScript",
        ".jsx": "React-компонент",
        ".scss": "SCSS-стили",
        ".css": "CSS-стили",
        ".svg": "SVG-иконка / изображение",
        ".png": "PNG-изображение",
        ".jpg": "JPEG-изображение",
        ".ico": "Favicon",
        ".pdf": "PDF-документ",
        ".pem": "TLS/JWT ключ",
        ".tf": "Terraform",
        ".hcl": "Terraform lock",
        ".tfvars": "Terraform переменные",
        ".tpl": "Helm template partial",
        ".tgz": "Vendored Helm subchart",
        ".lock": "Lockfile (Helm/composer/yarn)",
        ".html": "HTML",
        ".mts": "TypeScript (VitePress config)",
        ".ts": "TypeScript",
        ".mjs": "ES module (Node)",
        ".env": "Переменные окружения",
        ".xml": "XML-конфиг",
        ".zip": "Архив",
        ".tar": "Docker image tarball",
        ".woff": "Web-font",
        ".ttf": "TrueType font",
        ".eot": "Embedded OpenType font",
    }

    # Known files
    known = {
        "readme.md": "Главный README k3s-test",
        "plan-sentry-redmine.md": "План Redmine (Sentry удалён из контура)",
        "presentation-practical-guide.md": "Практическое руководство / демо для команды",
        ".gitignore": "Git ignore rules",
        "dockerfile": "Docker multistage build",
        "compose.yaml": "Docker Compose (Symfony)",
        "compose.override.yaml": "Локальные overrides Compose",
        "docker-compose.yml": "Docker Compose (моки / cabinet dev)",
        "package.json": "NPM/Yarn зависимости и scripts",
        "composer.json": "PHP Composer зависимости",
        "composer.lock": "Composer lockfile",
        "yarn.lock": "Yarn lockfile",
        "webpack.config.js": "Webpack Encore конфиг",
        "vite.config.js": "Vite bundler конфиг",
        "nginx.conf": "nginx конфиг контейнера",
        "index.php": "HTTP front controller Symfony",
        "index.html": "HTML entry (Vite/React)",
        "console": "Symfony CLI entry",
        "phpunit": "PHPUnit runner wrapper",
        "build.yml": "Gitea Actions CI pipeline",
        "config.mts": "VitePress: nav, sidebar, mermaid",
        "manifest.json": "Метаданные скриншотов",
        "env.js": "Runtime API URL (adminpanel)",
        "entrypoint.sh": "Container entrypoint (env injection)",
        "all.yaml": "Combined Helm template (Deployment/Service/Ingress)",
        "values.yaml": "Базовые Helm values",
        "values-test.yaml": "Overrides для test-контура",
        "values-stage.yaml": "Overrides для stage-контура",
        "chart.yaml": "Helm chart metadata",
        "app-of-apps.yaml": "ArgoCD root Application (sova-root)",
        "platform-tools.yaml": "ArgoCD: monitoring, Gitea Actions, Redmine",
        "test-contour.yaml": "ArgoCD: приложения test-контура",
        "sova-projects.yaml": "ArgoCD GitOps: AppProject definitions",
        "sova-project.yaml": "ArgoCD AppProject RBAC и namespaces",
        "db-init-jobs.yaml": "K8s Jobs: schema → seed SQL",
        "release-tag.sh": "Создать git tag → Gitea CI → GitOps",
        "bootstrap-multipass.sh": "Полный bootstrap VM + k3s + platform",
        "deploy-test-stack.sh": "Деплой приложений test-контура",
        "prepare-db-init.sh": "Генерация schema/seed SQL из monorepo",
        "sync-from-monorepo.sh": "Синхронизация кода из родительского monorepo",
        "use-kubeconfig.sh": "export KUBECONFIG=~/.kube/sova-test-config",
        "print-urls.sh": "URL всех сервисов и пароли platform",
        "smoke-test.sh": "Smoke-проверки HTTP + kubectl",
        "testsdk.js": "Stub WrSDK/SmartCaptcha для *.sova.local",
        "slideshow_controller.js": "Stimulus: lazy import owl.carousel",
        "services_stub.yaml": "Stub-клиенты SMS/Calltouch/Captcha для test",
        "services.php": "PHP DI bindings по APP_ENV",
    }
    if name.lower() in known:
        return known[name.lower()]

    script_desc = {
        "scripts/bootstrap-argocd.sh": "ArgoCD AppProject + Applications (sova-root, data-test, test-contour)",
        "scripts/bootstrap-gitea-ci-secrets.sh": "Gitea Actions secrets: registry, deploy SSH key",
        "scripts/bootstrap-gitea-runner.sh": "Установка Gitea Actions runner в k3s",
        "scripts/bootstrap-gitea.sh": "Bootstrap Gitea: org sova, repos, admin user",
        "scripts/bootstrap-redmine.sh": "REST API: проект sova-platform + задача #27",
        "scripts/bootstrap-vm.sh": "Generic VM bootstrap helper",
        "scripts/build-images.sh": "Сборка Docker-образов всех приложений (local-test/test tag)",
        "scripts/configure-k3s-registry.sh": "k3s registries.yaml → pull из git.sova.local",
        "scripts/deploy-monitoring-logs.sh": "Helm: Loki + Promtail (логи в Grafana)",
        "scripts/deploy-platform-ingress.sh": "Ingress rules: Gitea, ArgoCD, Grafana, Redmine, docs",
        "scripts/deploy-platform.sh": "Platform stack: ingress, ArgoCD, Gitea, Prometheus/Grafana",
        "scripts/deploy-redmine.sh": "Helm Redmine + ingress + ArgoCD app redmine-test",
        "scripts/deploy-sentry-redmine.sh": "Alias → deploy-redmine.sh (Sentry удалён)",
        "scripts/import-images-to-vm.sh": "docker load .images/*.tar в Multipass VM",
        "scripts/install-k3s-multipass.sh": "Установка k3s внутри Multipass VM",
        "scripts/k3d-bootstrap.sh": "k3d cluster + ingress + apps (Mac без Multipass)",
        "scripts/migrate-monorepo-branch.sh": "Demo: миграция ветки monorepo для issue #27",
        "scripts/prepare-db-init.py": "Split SQL на schema/seed (helper для prepare-db-init.sh)",
        "scripts/print-test-users.sh": "Тестовые логины/пароли приложений",
        "scripts/release-test-tag.sh": "Wrapper → release-tag.sh (backward compat)",
        "scripts/resize-multipass-vm.sh": "Увеличить CPU/RAM Multipass VM",
        "scripts/setup-git-flow-branches.sh": "Создать prod/test/stage в Gitea repos",
        "scripts/setup-gitea-branch-protection.sh": "Branch protection: PR-only на env-ветки",
        "scripts/setup-gitea-redmine-integration.sh": "Инструкции Gitea ↔ Redmine (manual UI)",
        "scripts/capture-platform-screenshots/capture.mjs": "Playwright: снять UI platform screenshots",
        "scripts/capture-platform-screenshots/harness-check.mjs": "Проверка prerequisites screenshot harness",
        "scripts/capture-platform-screenshots/reg-e2e.mjs": "E2E: сценарий регистрации cabinet",
        "scripts/capture-platform-screenshots/run.sh": "Entry point: полный pipeline скриншотов",
    }
    if rel in script_desc:
        return script_desc[rel]

    if "wiremock/mappings" in p or "charts/mocks/mappings" in p:
        stub = name.replace(".json", "").replace("-", " ")
        return f"WireMock stub: {stub}"
    if "/migrations/version" in p:
        return "Doctrine migration"
    if "/entity/" in p:
        return f"Doctrine entity: {name.replace('.php', '')}"
    if "/repository/" in p:
        return f"Doctrine repository: {name.replace('.php', '')}"
    if "/controller/" in p and ext == ".php":
        return f"Symfony controller: {name.replace('.php', '')}"
    if "/command/" in p and ext == ".php":
        return f"Console command: {name.replace('.php', '')}"
    if "/service/" in p and ext == ".php":
        return f"Service: {name.replace('.php', '')}"
    if "/dto/" in p or "/dto\\" in p:
        return f"DTO: {name.replace('.php', '')}"
    if "/form/" in p and ext == ".php":
        return f"Form type: {name.replace('.php', '')}"
    if "/messagehandler/" in p:
        return f"Messenger handler: {name.replace('.php', '')}"
    if "/message/" in p and ext == ".php":
        return f"Messenger message: {name.replace('.php', '')}"
    if "/controllers/" in p and name.endswith("_controller.js"):
        return f"Stimulus controller: {name.replace('_controller.js', '')}"
    if "/pages/" in p and ext == ".jsx":
        return f"React page: {name.replace('.jsx', '')}"
    if "/api/api" in p and ext == ".js":
        return f"RTK Query API slice: {name.replace('.js', '')}"
    if "/components/" in p and ext == ".jsx":
        return f"React component: {name.replace('.jsx', '')}"
    if "/hooks/" in p and ext == ".jsx":
        return f"React hook: {name.replace('.jsx', '')}"
    if "/templates/" in p and ext == ".twig":
        return f"Twig template: {rel.split('templates/')[-1]}"
    if "/config/packages/" in p:
        return f"Symfony bundle config: {name}"
    if "/assets/sass/" in p:
        return f"SCSS entry: {name}"
    if "/screenshots/" in p and ext == ".png":
        return f"Скриншот UI: {name}"
    if "/forms-screenshots/" in p and ext == ".png":
        return f"Скриншот формы cabinet: {name}"
    if "/backend-scenarios/" in p:
        return f"Сценарий backend: {name.replace('.md', '')}"
    if "/apps/" in p and ext == ".md":
        return f"Документация приложения: {name.replace('.md', '')}"
    if "/infrastructure/" in p and ext == ".md":
        return f"Инфра-документация: {name.replace('.md', '')}"
    if "platform-credentials.env" in p:
        return "Сгенерированные креды platform (не в git)"
    if ".images/" in p and ext == ".tar":
        return f"Saved Docker image для import-images-to-vm.sh"
    if "ci-ssh/" in p:
        return "SSH-ключ Gitea Actions → sova-deploy GitOps"

    if ext in ext_map:
        return ext_map[ext]
    return "Файл проекта"


def collect(prefix: str) -> list[tuple[str, str]]:
    base = ROOT / prefix if prefix else ROOT
    files: list[tuple[str, str]] = []
    for path in sorted(base.rglob("*")):
        if not path.is_file():
            continue
        rel = path.relative_to(ROOT).as_posix()
        if should_skip(rel):
            continue
        if prefix and not rel.startswith(prefix.rstrip("/")):
            continue
        files.append((rel, describe(rel)))
    return files


def md_table(rows: list[tuple[str, str]], path_col: str = "Путь") -> str:
    if not rows:
        return "_Нет файлов._\n"
    lines = [f"| {path_col} | Назначение |", "|------|------------|"]
    for rel, desc in rows:
        lines.append(f"| `{rel}` | {desc} |")
    return "\n".join(lines) + "\n"


def group_by_dir(files: list[tuple[str, str]]) -> dict[str, list[tuple[str, str]]]:
    groups: dict[str, list[tuple[str, str]]] = {}
    for rel, desc in files:
        parent = str(Path(rel).parent)
        groups.setdefault(parent if parent != "." else "(root)", []).append((rel, desc))
    return dict(sorted(groups.items()))


def write_page(filename: str, title: str, intro: str, files: list[tuple[str, str]], grouped: bool = True) -> None:
    body = [f"# {title}\n", intro, f"\n**Файлов:** {len(files)}\n"]
    if grouped:
        for dirname, rows in group_by_dir(files).items():
            body.append(f"\n## `{dirname}/`\n\n")
            body.append(md_table(rows, "Файл"))
    else:
        body.append("\n")
        body.append(md_table(files))
    (OUT / filename).write_text("\n".join(body), encoding="utf-8")


SECTIONS = [
    ("scripts.md", "scripts/", "Скрипты k3s-test", "Все shell/Python/Node скрипты bootstrap, deploy, CI и утилит. Запускать из каталога `k3s-test/`."),
    ("sova-deploy.md", "sova-deploy/", "sova-deploy: Helm и ArgoCD", "GitOps-репозиторий: Helm charts приложений, data layer, ArgoCD Applications и platform values."),
    ("sova-platform.md", "sova-platform/", "sova-platform: Terraform", "Terraform для Multipass VM и установки k3s на single-node."),
    ("sova-mocks.md", "sova-mocks/", "sova-mocks: WireMock и Mailpit", "Моки внешних API (MIS, Calltouch, Captcha) и SMTP для test-контура."),
    ("sova-redmine.md", "sova-redmine/", "sova-redmine: custom image", "Опциональный custom Docker-образ Redmine с plugin github_hook."),
    ("docs-pointers.md", "docs/", "docs/: указатели", "Короткие markdown-файлы со ссылками на VitePress."),
    ("sova-backend.md", "sova-backend/", "sova-backend: Symfony API", "Backend API для adminpanel и интеграций. Копия из monorepo + test-специфичные правки."),
    ("sova-adminpanel.md", "sova-adminpanel/", "sova-adminpanel: React admin", "React + Vite admin panel для CRUD контента и специалистов."),
    ("sova-cabinet.md", "sova-cabinet/", "sova-cabinet: Symfony ЛК", "Личный кабинет пациента: регистрация, запись, оплата."),
    ("sova-docs-repo.md", "sova-docs/", "sova-docs: сайт документации", "VitePress-сайт (монорепо docs + test-contour). Собирается в Docker и деплоится как docs-test."),
]

ROOT_FILES = [
    "README.md", "plan-sentry-redmine.md", "presentation-practical-guide.md", ".gitignore",
]


def main() -> None:
    for filename, prefix, title, intro in SECTIONS:
        files = collect(prefix)
        write_page(filename, title, intro, files)

    # Root + generated + images
    root_rows: list[tuple[str, str]] = []
    for name in ROOT_FILES:
        p = ROOT / name
        if p.exists():
            root_rows.append((name, describe(name)))
    for prefix in [".generated/", ".images/"]:
        root_rows.extend(collect(prefix))

    write_page(
        "root-and-artifacts.md",
        "Корень k3s-test и артеfacts",
        "Файлы в корне `k3s-test/`, сгенерированные креды и tar-образы для offline import.\n\n"
        "> **Не документируем:** `.tmp-chart/` (legacy Sentry chart, 456 upstream-файлов), "
        "`vendor/`, `node_modules/`, `public/build/` (сборка Webpack), `.terraform/providers/`.",
        root_rows,
        grouped=False,
    )

    # Index
    total = sum(len(collect(p)) for _, p, _, _ in SECTIONS) + len(root_rows)
    index = [
        "# Справочник файлов k3s-test\n",
        "Полный перечень файлов песочницы `k3s-test/` с кратким назначением каждого.",
        "Для понимания **как пользоваться** контуром начните с [обзора test-контура](../) и [статьи «что сделано»](../test-contour-article).",
        "Этот справочник отвечает на вопрос **«что лежит в каком файле»**.\n",
        f"**Документировано файлов:** ~{total} (без vendor/node_modules/dist/.tmp-chart).\n",
        "## Дерево каталогов\n",
        "```",
        "k3s-test/",
        "├── README.md, plan-sentry-redmine.md, presentation-practical-guide.md",
        "├── .generated/          # platform-credentials.env, CI SSH keys",
        "├── .images/             # *.tar для import-images-to-vm.sh",
        "├── docs/                  # указатели на VitePress",
        "├── scripts/               # bootstrap, deploy, CI, smoke",
        "├── sova-adminpanel/       # React admin + Gitea CI",
        "├── sova-backend/          # Symfony API + Gitea CI",
        "├── sova-cabinet/          # Symfony ЛК + Gitea CI",
        "├── sova-deploy/           # Helm + ArgoCD GitOps",
        "├── sova-docs/             # VitePress documentation site",
        "├── sova-mocks/            # WireMock + Mailpit",
        "├── sova-platform/         # Terraform k3s bootstrap",
        "└── sova-redmine/          # custom Redmine image (optional)",
        "```\n",
        "## Разделы справочника\n",
        "| Раздел | Файлов | Описание |",
        "|--------|--------|----------|",
    ]
    for filename, prefix, title, _ in SECTIONS:
        n = len(collect(prefix))
        link = filename.replace(".md", "")
        index.append(f"| [{title}](./{link}) | {n} | `{prefix}` |")
    index.append(f"| [Корень и артеfacts](./root-and-artifacts) | {len(root_rows)} | README, `.generated/`, `.images/` |")
    index.extend([
        "\n## Типовые сценарии (какие скрипты вызывать)\n",
        "| Сценарий | Команды |",
        "|----------|---------|",
        "| **Первый запуск (Multipass)** | `bootstrap-multipass.sh` → `build-images.sh` → `import-images-to-vm.sh` → `deploy-platform.sh` → `deploy-test-stack.sh` |",
        "| **Первый запуск (k3d на Mac)** | `sync-from-monorepo.sh` → `build-images.sh` → `k3d-bootstrap.sh` |",
        "| **Старт/стоп VM** | `multipass start sova-test` / `multipass stop sova-test` → `source scripts/use-kubeconfig.sh` |",
        "| **Релиз приложения** | `scripts/release-tag.sh {backend\\|adminpanel\\|cabinet\\|docs} {tag} test` |",
        "| **Обновить БД test** | `prepare-db-init.sh` → удалить job db-init → redeploy data-test |",
        "| **Redmine** | `deploy-redmine.sh --bootstrap` |",
        "| **Скриншоты для доков** | `capture-platform-screenshots/run.sh` |",
        "\n## Связанная документация\n",
        "- [Git-flow](../git-flow) — ветки prod/test/stage",
        "- [Система тегов](../tags) — `{component}-v{semver}-{env}`",
        "- [ArgoCD приложения](../argocd-apps) — sova-root, data-test",
        "- [Gitea CI](./guides/gitea-ci) — pipeline и registry",
        "- [Redmine](./guides/redmine) — issue tracker",
    ])
    (OUT / "index.md").write_text("\n".join(index), encoding="utf-8")
    print(f"Generated {len(SECTIONS)+2} pages, ~{total} files")


if __name__ == "__main__":
    main()
