package tech.easyflow.skill.imports;

import com.easyagents.skill.util.SkillPaths;
import org.springframework.stereotype.Service;
import tech.easyflow.common.web.exceptions.BusinessException;
import tech.easyflow.skill.entity.Skill;
import tech.easyflow.skill.entity.SkillAsset;
import tech.easyflow.skill.entity.SkillReference;
import tech.easyflow.skill.entity.SkillScript;
import tech.easyflow.skill.service.SkillService;
import tech.easyflow.skill.store.DBSkillContentStore;

import java.io.IOException;
import java.io.OutputStream;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * Skill zip 导出服务实现。
 */
@Service
public class SkillExportServiceImpl implements SkillExportService {

    private final SkillService skillService;
    private final DBSkillContentStore contentStore;

    /**
     * 创建 Skill 导出服务。
     *
     * @param skillService Skill 服务
     * @param contentStore Skill asset 内容存储
     */
    public SkillExportServiceImpl(SkillService skillService, DBSkillContentStore contentStore) {
        this.skillService = skillService;
        this.contentStore = contentStore;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void exportZip(Collection<BigInteger> skillIds, OutputStream outputStream) {
        if (skillIds == null || skillIds.isEmpty()) {
            throw new BusinessException("请选择要导出的 Skill");
        }
        try (ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream, StandardCharsets.UTF_8)) {
            Set<String> folderNames = new LinkedHashSet<>();
            for (BigInteger skillId : skillIds) {
                Skill skill = skillService.getDetail(skillId);
                writeSkill(zipOutputStream, folderNames, skill);
            }
        } catch (IOException e) {
            throw new BusinessException("导出 Skill 失败");
        }
    }

    private void writeSkill(ZipOutputStream zipOutputStream, Set<String> folderNames, Skill skill) throws IOException {
        String folder = uniqueFolderName(folderNames, skill.getName());
        writeText(zipOutputStream, folder + "/" + SkillPaths.SKILL_FILE, skill.getSkillContent());
        if (skill.getReferences() != null) {
            for (SkillReference reference : skill.getReferences()) {
                writeText(zipOutputStream, folder + "/" + reference.getPath(), reference.getContent());
            }
        }
        if (skill.getScripts() != null) {
            for (SkillScript script : skill.getScripts()) {
                writeText(zipOutputStream, folder + "/" + script.getPath(), script.getContent());
            }
        }
        if (skill.getAssets() != null) {
            for (SkillAsset asset : skill.getAssets()) {
                zipOutputStream.putNextEntry(new ZipEntry(folder + "/" + asset.getPath()));
                zipOutputStream.write(contentStore.readAllBytes(asset.getContentRef()));
                zipOutputStream.closeEntry();
            }
        }
    }

    private void writeText(ZipOutputStream zipOutputStream, String path, String content) throws IOException {
        zipOutputStream.putNextEntry(new ZipEntry(path));
        zipOutputStream.write((content == null ? "" : content).getBytes(StandardCharsets.UTF_8));
        zipOutputStream.closeEntry();
    }

    private String uniqueFolderName(Set<String> folderNames, String name) {
        String base = sanitizeFolderName(name);
        String candidate = base;
        int index = 2;
        while (!folderNames.add(candidate)) {
            candidate = base + "-" + index++;
        }
        return candidate;
    }

    private String sanitizeFolderName(String value) {
        String sanitized = value == null ? "skill" : value.trim().replaceAll("[\\\\/:*?\"<>|\\s]+", "-");
        sanitized = sanitized.replaceAll("^-+", "").replaceAll("-+$", "");
        return sanitized.isBlank() ? "skill" : sanitized;
    }
}

