from __future__ import annotations

import tempfile
import unittest
from pathlib import Path

from presmoke.readme_spec import parse_readme, split_commands


README = """# sample

## 编译运行

- 配置环境变量
  ```bash
  source /usr/local/Ascend/cann/set_env.sh
  ```
- 样例执行
  ```bash
  SCENARIO=0
  mkdir -p build && cd build; # comment
  cmake -DSCENARIO_NUM=${SCENARIO} -DCMAKE_ASC_ARCHITECTURES=dav-3510 ..;make -j;
  python3 ../scripts/gen_data.py ${SCENARIO}
  ./demo
  python3 ../scripts/verify_result.py output/output.bin output/golden.bin
  ```

- 编译选项说明
| 参数 | 说明 | 可选值 | 默认值 |
| :--- | :--- | :--- | :--- |
| CMAKE_ASC_RUN_MODE | 运行模式 | npu, sim | npu |
| CMAKE_ASC_ARCHITECTURES | NPU硬件架构 | dav-3510 | dav-3510 |
"""


class ReadmeSpecTest(unittest.TestCase):
    def test_split_commands_keeps_env_and_classifies(self) -> None:
        commands = split_commands("SCENARIO=0\ncmake ..; make -j && ./demo")
        self.assertEqual([c.kind for c in commands], ["cmake", "make", "run"])
        self.assertEqual(commands[0].env["SCENARIO"], "0")
        self.assertEqual(commands[-1].env["SCENARIO"], "0")

    def test_parse_readme_extracts_sample_block_arch_and_modes(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            root = Path(tmp) / "examples"
            ex = root / "x"
            (ex / "scripts").mkdir(parents=True)
            (ex / "README.md").write_text(README, encoding="utf-8")
            (ex / "scripts" / "gen_data.py").write_text("", encoding="utf-8")
            (ex / "scripts" / "verify_result.py").write_text("", encoding="utf-8")
            spec = parse_readme(ex, root)
        self.assertEqual(spec.source, "readme")
        self.assertIn("dav-3510", spec.archs)
        self.assertEqual(spec.modes, ["npu", "sim"])
        self.assertTrue(any(c.kind == "verify" for c in spec.commands))

    def test_support_product_section_overrides_command_arch_defaults(self) -> None:
        text = """# sample

## 支持的产品

- Ascend 950PR/Ascend 950DT
- Atlas A3 训练系列产品/Atlas A3 推理系列产品
- Atlas A2 训练系列产品/Atlas A2 推理系列产品

## 编译运行

```bash
cmake -S . -B build -DCMAKE_ASC_ARCHITECTURES=dav-2201
cmake --build build -j
./demo
```
"""
        with tempfile.TemporaryDirectory() as tmp:
            root = Path(tmp) / "examples"
            ex = root / "x"
            ex.mkdir(parents=True)
            (ex / "README.md").write_text(text, encoding="utf-8")
            spec = parse_readme(ex, root)

        self.assertEqual(spec.archs, ["dav-2201", "dav-3510"])

    def test_support_product_section_restricts_arch_even_if_option_table_mentions_more(self) -> None:
        text = """# sample

## 支持的产品

- Atlas A3 训练系列产品/Atlas A3 推理系列产品
- Atlas A2 训练系列产品/Atlas A2 推理系列产品

## 编译运行

```bash
cmake -DCMAKE_ASC_ARCHITECTURES=dav-2201 ..;make -j;
./demo
```

| 参数 | 说明 |
| :--- | :--- |
| CMAKE_ASC_ARCHITECTURES | dav-2201 对应 Atlas A2/A3,dav-3510 对应 Ascend 950PR/Ascend 950DT |
"""
        with tempfile.TemporaryDirectory() as tmp:
            root = Path(tmp) / "examples"
            ex = root / "x"
            ex.mkdir(parents=True)
            (ex / "README.md").write_text(text, encoding="utf-8")
            spec = parse_readme(ex, root)

        self.assertEqual(spec.archs, ["dav-2201"])

    def test_parse_readme_prefers_cmake_block_over_manual_compile_block(self) -> None:
        text = """# sample

## 编译运行

- 样例执行

  - 命令行方式

    ```bash
    bisheng main.cpp -o demo -L./ \\
      -lfoo
    ./demo
    ```

  - CMake方式

    ```bash
    mkdir -p build && cd build;
    cmake -DCMAKE_ASC_ARCHITECTURES=dav-3510 ..;make -j;
    ./demo
    ```
"""
        with tempfile.TemporaryDirectory() as tmp:
            root = Path(tmp) / "examples"
            ex = root / "x"
            ex.mkdir(parents=True)
            (ex / "README.md").write_text(text, encoding="utf-8")
            (ex / "CMakeLists.txt").write_text("add_executable(demo main.cpp)", encoding="utf-8")
            spec = parse_readme(ex, root)
        self.assertIn("cmake", " ".join(c.raw for c in spec.commands))
        self.assertNotIn("-lfoo", " ".join(c.raw for c in spec.commands))
        self.assertEqual([c.kind for c in spec.commands][-3:], ["cmake", "make", "run"])

    def test_split_commands_joins_shell_line_continuations(self) -> None:
        commands = split_commands("bisheng main.cpp -o demo -L./ \\\n  -lfoo\n./demo")
        self.assertEqual(len(commands), 2)
        self.assertIn("-lfoo", commands[0].raw)
        self.assertNotIn("\\", commands[0].raw)


if __name__ == "__main__":
    unittest.main()