package tech.easyflow.skill.gitimport;

import org.eclipse.jgit.api.Git;
import org.junit.Test;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashSet;
import java.util.Set;
import java.util.zip.ZipInputStream;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

/**
 * {@link SkillGitCandidateScanner} 固定提交扫描与标准包组装测试。
 */
public class SkillGitCandidateScannerTest {

    /**
     * 发现根目录和嵌套 Skill，并把不可解析的 LFS 资源标为需处理。
     *
     * @throws Exception 仓库或 ZIP 读写失败
     */
    @Test
    public void discoversCandidatesAndCreatesIndependentStandardZip() throws Exception {
        SkillGitImportProperties properties = new SkillGitImportProperties();
        SkillGitCandidateScanner scanner = new SkillGitCandidateScanner(properties);
        Path directory = Files.createTempDirectory("skill-git-scanner-test-");
        try (Git git = Git.init().setDirectory(directory.toFile()).call()) {
            write(directory.resolve("SKILL.md"), skill("root-skill", "根目录技能"));
            write(directory.resolve("references/guide.md"), "# Guide\n");
            write(directory.resolve("nested-skill/SKILL.md"), skill("nested-skill", "嵌套技能"));
            write(directory.resolve("nested-skill/assets/model.bin"),
                    "version https://git-lfs.github.com/spec/v1\noid sha256:abc\nsize 10\n");
            git.add().addFilepattern(".").call();
            String commitSha = git.commit().setMessage("test")
                    .setAuthor("EasyFlow", "test@easyflow.local")
                    .setCommitter("EasyFlow", "test@easyflow.local").call().getName();
            SkillGitRepositoryReader.Snapshot snapshot = new SkillGitRepositoryReader.Snapshot(
                    git.getRepository(), directory, "refs/heads/master", commitSha);

            SkillGitRepositoryScan scan = scanner.scan(snapshot);

            assertEquals(scan.candidates().size(), 2);
            SkillGitScanResult.Candidate root = candidate(scan, "root-skill");
            SkillGitScanResult.Candidate nested = candidate(scan, "nested-skill");
            assertTrue(root.importable());
            assertFalse(nested.importable());
            assertTrue(nested.issues().stream()
                    .anyMatch(issue -> "GIT_LFS_UNRESOLVED".equals(issue.code())));

            Path archive = scanner.createStandardZip(snapshot, scan, root.candidateId());
            try {
                assertEquals(zipEntries(archive),
                        Set.of("root-skill/SKILL.md", "root-skill/references/guide.md"));
            } finally {
                scanner.deleteArchive(archive);
            }
            // Snapshot 与 Git 共享 Repository，交给 Git 的 try-with-resources 统一关闭。
        } finally {
            deleteDirectory(directory);
        }
    }

    private SkillGitScanResult.Candidate candidate(SkillGitRepositoryScan scan, String name) {
        return scan.candidates().stream().filter(item -> name.equals(item.name())).findFirst()
                .orElseThrow();
    }

    private Set<String> zipEntries(Path archive) throws IOException {
        Set<String> entries = new HashSet<>();
        try (ZipInputStream input = new ZipInputStream(Files.newInputStream(archive))) {
            java.util.zip.ZipEntry entry;
            while ((entry = input.getNextEntry()) != null) {
                entries.add(entry.getName());
            }
        }
        return entries;
    }

    private String skill(String name, String description) {
        return "---\nname: " + name + "\ndescription: " + description + "\n---\n# " + name + "\n";
    }

    private void write(Path path, String content) throws IOException {
        Files.createDirectories(path.getParent());
        Files.writeString(path, content, StandardCharsets.UTF_8);
    }

    private void deleteDirectory(Path directory) throws IOException {
        if (!Files.exists(directory)) {
            return;
        }
        try (java.util.stream.Stream<Path> paths = Files.walk(directory)) {
            for (Path path : paths.sorted(java.util.Comparator.reverseOrder()).toList()) {
                Files.deleteIfExists(path);
            }
        }
    }
}
