package com.easyagents.skill.repository.memory;

import com.easyagents.skill.exception.SkillValidationException;
import com.easyagents.skill.model.*;
import com.easyagents.skill.repository.SkillRepository;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * 基于内存的 Skill 聚合仓储实现。
 */
public class InMemorySkillRepository implements SkillRepository {

    private final ConcurrentMap<String, Skill> skills = new ConcurrentHashMap<>();

    /**
     * 保存 Skill 聚合。
     *
     * @param skill Skill 聚合
     */
    @Override
    public void save(Skill skill) {
        if (skill == null || isBlank(skill.getId())) {
            throw new SkillValidationException("Skill id is required.");
        }
        skills.put(skill.getId(), copySkill(skill));
    }

    /**
     * 获取完整 Skill。
     *
     * @param skillId Skill ID
     * @return Skill 聚合
     */
    @Override
    public Optional<Skill> get(String skillId) {
        Skill skill = skills.get(skillId);
        return skill == null ? Optional.empty() : Optional.of(copySkill(skill));
    }

    /**
     * 获取 Skill 描述。
     *
     * @param skillId Skill ID
     * @return Skill 描述
     */
    @Override
    public Optional<SkillDescriptor> getDescriptor(String skillId) {
        Skill skill = skills.get(skillId);
        return skill == null ? Optional.empty() : Optional.of(copyDescriptor(skill.toDescriptor()));
    }

    /**
     * 列出 Skill 描述。
     *
     * @return Skill 描述列表
     */
    @Override
    public List<SkillDescriptor> listDescriptors() {
        List<SkillDescriptor> descriptors = new ArrayList<>();
        for (Skill skill : skills.values()) {
            descriptors.add(copyDescriptor(skill.toDescriptor()));
        }
        return descriptors;
    }

    /**
     * 删除 Skill。
     *
     * @param skillId Skill ID
     */
    @Override
    public void delete(String skillId) {
        skills.remove(skillId);
    }

    /**
     * 判断 Skill 是否存在。
     *
     * @param skillId Skill ID
     * @return 存在时为 true
     */
    @Override
    public boolean exists(String skillId) {
        return skills.containsKey(skillId);
    }

    private static Skill copySkill(Skill source) {
        Skill target = new Skill();
        target.setId(source.getId());
        target.setPackageRoot(source.getPackageRoot());
        target.setName(source.getName());
        target.setDescription(source.getDescription());
        target.setMetadata(copyMetadata(source.getMetadata()));
        SkillDocument copiedDocument = copyDocument(source.getDocument());
        if (copiedDocument == null) {
            target.setSkillContent(source.getSkillContent());
        } else {
            target.setDocument(copiedDocument);
        }
        target.setResources(copyResources(source.getResources()));
        target.setReferences(copyReferences(source.getReferences()));
        target.setScripts(copyScripts(source.getScripts()));
        target.setAssets(copyAssets(source.getAssets()));
        return target;
    }

    private static SkillDocument copyDocument(SkillDocument source) {
        if (source == null) {
            return null;
        }
        SkillDocument target = new SkillDocument(source.getRawContent(),
                source.getFrontmatter().getValues(), source.getMarkdownBody(),
                source.getFrontmatterLocations(), source.getDiagnostics());
        target.setModified(source.isModified());
        return target;
    }

    private static List<SkillResource> copyResources(List<SkillResource> sources) {
        List<SkillResource> targets = new ArrayList<>();
        if (sources == null) {
            return targets;
        }
        for (SkillResource source : sources) {
            SkillResource target = new SkillResource();
            target.setPath(source.getPath());
            target.setKind(source.getKind());
            target.setMediaType(source.getMediaType());
            target.setTextContent(source.getTextContent());
            target.setContentRef(source.getContentRef());
            target.setContentHash(source.getContentHash());
            target.setSize(source.getSize());
            target.setMetadata(copyMetadata(source.getMetadata()));
            targets.add(target);
        }
        return targets;
    }

    private static List<SkillReference> copyReferences(List<SkillReference> sources) {
        List<SkillReference> targets = new ArrayList<>();
        if (sources == null) {
            return targets;
        }
        for (SkillReference source : sources) {
            SkillReference target = new SkillReference();
            target.setPath(source.getPath());
            target.setName(source.getName());
            target.setContent(source.getContent());
            target.setContentHash(source.getContentHash());
            target.setSize(source.getSize());
            target.setMetadata(copyMetadata(source.getMetadata()));
            targets.add(target);
        }
        return targets;
    }

    private static List<SkillScript> copyScripts(List<SkillScript> sources) {
        List<SkillScript> targets = new ArrayList<>();
        if (sources == null) {
            return targets;
        }
        for (SkillScript source : sources) {
            SkillScript target = new SkillScript();
            target.setPath(source.getPath());
            target.setLanguage(source.getLanguage());
            target.setContent(source.getContent());
            target.setContentHash(source.getContentHash());
            target.setSize(source.getSize());
            target.setMetadata(copyMetadata(source.getMetadata()));
            targets.add(target);
        }
        return targets;
    }

    private static List<SkillAsset> copyAssets(List<SkillAsset> sources) {
        List<SkillAsset> targets = new ArrayList<>();
        if (sources == null) {
            return targets;
        }
        for (SkillAsset source : sources) {
            SkillAsset target = new SkillAsset();
            target.setPath(source.getPath());
            target.setName(source.getName());
            target.setMediaType(source.getMediaType());
            target.setContentRef(source.getContentRef());
            target.setContentHash(source.getContentHash());
            target.setSize(source.getSize());
            target.setMetadata(copyMetadata(source.getMetadata()));
            targets.add(target);
        }
        return targets;
    }

    private static SkillDescriptor copyDescriptor(SkillDescriptor source) {
        return new SkillDescriptor(
                source.getId(),
                source.getName(),
                source.getDescription(),
                copyMetadata(source.getMetadata())
        );
    }

    private static SkillMetadata copyMetadata(SkillMetadata source) {
        return source == null ? new SkillMetadata() : new SkillMetadata(source.getValues());
    }

    private static boolean isBlank(String value) {
        return value == null || value.isBlank();
    }
}
