package tech.easyflow.skill.imports;

import com.easyagents.skill.codec.ZipSkillPackageCodec;
import com.easyagents.skill.util.SkillHashes;
import com.mybatisflex.core.query.QueryWrapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tech.easyflow.ai.enums.PublishStatus;
import tech.easyflow.common.web.exceptions.BusinessException;
import tech.easyflow.skill.entity.Skill;
import tech.easyflow.skill.service.SkillService;
import tech.easyflow.skill.store.DBSkillContentStore;
import tech.easyflow.skill.support.SkillModelConverter;

import java.io.InputStream;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * Skill zip 导入服务实现。
 */
@Service
public class SkillImportServiceImpl implements SkillImportService {

    private final SkillService skillService;
    private final DBSkillContentStore contentStore;

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

    /**
     * {@inheritDoc}
     */
    @Override
    public SkillImportPreview preview(InputStream inputStream) {
        List<com.easyagents.skill.model.Skill> importedSkills = new ZipSkillPackageCodec().importZip(inputStream);
        SkillImportPreview preview = new SkillImportPreview();
        preview.setSkills(importedSkills.stream().map(this::toPreviewItem).toList());
        return preview;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Skill> importZip(InputStream inputStream, BigInteger categoryId, boolean overwriteDraft) {
        List<com.easyagents.skill.model.Skill> importedSkills = new ZipSkillPackageCodec(contentStore).importZip(inputStream);
        List<Skill> savedSkills = new ArrayList<>();
        for (com.easyagents.skill.model.Skill imported : importedSkills) {
            Skill existing = findByName(imported.getName());
            if (existing != null) {
                if (!overwriteDraft || !PublishStatus.DRAFT.getCode().equals(existing.getPublishStatus())) {
                    throw new BusinessException("Skill 已存在，且不允许覆盖：" + imported.getName());
                }
                Skill replacement = SkillModelConverter.fromAgentSkill(imported);
                replacement.setId(existing.getId());
                replacement.setCategoryId(categoryId);
                replacement.setSourceType("ZIP");
                replacement.setPackageHash(SkillHashes.sha256Hex(imported.getSkillContent().getBytes(StandardCharsets.UTF_8)));
                savedSkills.add(skillService.updateDraft(replacement));
            } else {
                Skill skill = SkillModelConverter.fromAgentSkill(imported);
                skill.setCategoryId(categoryId);
                skill.setSourceType("ZIP");
                skill.setPackageHash(SkillHashes.sha256Hex(imported.getSkillContent().getBytes(StandardCharsets.UTF_8)));
                savedSkills.add(skillService.saveDraft(skill));
            }
        }
        return savedSkills;
    }

    private SkillImportPreviewItem toPreviewItem(com.easyagents.skill.model.Skill skill) {
        SkillImportPreviewItem item = new SkillImportPreviewItem();
        item.setPackageId(skill.getId());
        item.setName(skill.getName());
        item.setDescription(skill.getDescription());
        item.setReferenceCount(skill.getReferences().size());
        item.setScriptCount(skill.getScripts().size());
        item.setAssetCount(skill.getAssets().size());
        item.setConflict(findByName(skill.getName()) != null);
        return item;
    }

    private Skill findByName(String name) {
        if (name == null || name.isBlank()) {
            return null;
        }
        List<Skill> skills = skillService.list(QueryWrapper.create().eq(Skill::getName, name));
        return skills.isEmpty() ? null : skills.get(0);
    }
}
