#!/usr/bin/env python3
"""
Append source code listings to a Markdown report.

Usage example:
  python3 Report/append_sources_to_report.py \
    --input Report/lab2/zivro-lab2-report.md \
    --output Report/lab2/zivro-lab2-report-with-code.md \
    --base . \
    --include "Minint/**/*.cs" \
    --include "Minint.Core/**/*.cs" \
    --include "Minint.Infrastructure/**/*.cs" \
    --include "Minint.Tests/**/*.cs"
"""

from __future__ import annotations

import argparse
from pathlib import Path


EXT_TO_LANG: dict[str, str] = {
    ".cs": "csharp",
    ".axaml": "xml",
    ".xml": "xml",
    ".json": "json",
    ".md": "markdown",
    ".sh": "bash",
    ".py": "python",
}


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(description="Append code listings to report markdown.")
    parser.add_argument("--input", required=True, help="Path to source markdown report.")
    parser.add_argument("--output", required=True, help="Path to resulting markdown report.")
    parser.add_argument(
        "--base",
        default=".",
        help="Project root path used for resolving include patterns.",
    )
    parser.add_argument(
        "--include",
        action="append",
        default=[],
        help="Glob pattern relative to --base. Can be passed multiple times.",
    )
    parser.add_argument(
        "--exclude-substring",
        action="append",
        default=["/bin/", "/obj/", ".git/"],
        help="Skip files that contain this substring in path.",
    )
    parser.add_argument(
        "--title",
        default="Приложение A. Исходные тексты",
        help="Heading title for generated appendix.",
    )
    return parser.parse_args()


def detect_lang(path: Path) -> str:
    return EXT_TO_LANG.get(path.suffix.lower(), "text")


def should_skip(path: Path, excludes: list[str]) -> bool:
    normalized = str(path).replace("\\", "/")
    return any(sub in normalized for sub in excludes)


def collect_files(base: Path, patterns: list[str], excludes: list[str]) -> list[Path]:
    files: list[Path] = []
    seen: set[Path] = set()
    for pattern in patterns:
        for p in base.glob(pattern):
            if not p.is_file():
                continue
            if should_skip(p, excludes):
                continue
            rp = p.resolve()
            if rp in seen:
                continue
            seen.add(rp)
            files.append(rp)
    files.sort(key=lambda p: str(p).replace("\\", "/"))
    return files


def build_appendix(base: Path, files: list[Path], title: str) -> str:
    lines: list[str] = []
    lines.append("")
    lines.append("---")
    lines.append("")
    lines.append(f"## {title}")
    lines.append("")
    lines.append(
        f"Сформировано автоматически скриптом `Report/append_sources_to_report.py` (файлов: {len(files)})."
    )
    lines.append("")

    for i, file_path in enumerate(files, start=1):
        rel = file_path.relative_to(base).as_posix()
        lang = detect_lang(file_path)
        content = file_path.read_text(encoding="utf-8", errors="replace").rstrip()
        lines.append(f"### A.{i}. `{rel}`")
        lines.append("")
        lines.append(f"```{lang}")
        if content:
            lines.append(content)
        lines.append("```")
        lines.append("")

    return "\n".join(lines)


def main() -> int:
    args = parse_args()

    input_md = Path(args.input).resolve()
    output_md = Path(args.output).resolve()
    base = Path(args.base).resolve()
    patterns = args.include or ["**/*.cs"]

    if not input_md.is_file():
        raise FileNotFoundError(f"Input markdown not found: {input_md}")
    if not base.exists():
        raise FileNotFoundError(f"Base path not found: {base}")

    report_body = input_md.read_text(encoding="utf-8")
    files = collect_files(base, patterns, args.exclude_substring)
    appendix = build_appendix(base, files, args.title)

    output_md.parent.mkdir(parents=True, exist_ok=True)
    output_md.write_text(report_body.rstrip() + "\n" + appendix + "\n", encoding="utf-8")

    print(f"Input: {input_md}")
    print(f"Output: {output_md}")
    print(f"Files appended: {len(files)}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
