package com.easyagents.skill.model;

import com.easyagents.skill.util.SkillFrontmatter;
import com.easyagents.skill.validation.SkillValidationIssue;

import java.io.Serial;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 解析后的 SKILL.md 文档，保留原文并支持确定性重建。
 */
public class SkillDocument implements Serializable {

    @Serial
    private static final long serialVersionUID = 1L;

    private String rawContent;
    private SkillMetadata frontmatter = new SkillMetadata();
    private String markdownBody = "";
    private Map<String, SkillSourceLocation> frontmatterLocations = new LinkedHashMap<>();
    private List<SkillValidationIssue> diagnostics = new ArrayList<>();
    private boolean modified;

    /**
     * 创建空文档。
     */
    public SkillDocument() {
    }

    /**
     * 创建已解析文档。
     *
     * @param rawContent 原始完整内容
     * @param frontmatter frontmatter 有序对象
     * @param markdownBody Markdown 正文
     */
    public SkillDocument(String rawContent, Map<String, Object> frontmatter, String markdownBody) {
        this(rawContent, frontmatter, markdownBody, Map.of(), List.of());
    }

    /**
     * 创建包含源码定位和解析诊断的已解析文档。
     *
     * @param rawContent 原始完整内容
     * @param frontmatter frontmatter 有序对象
     * @param markdownBody Markdown 正文
     * @param frontmatterLocations 顶层 frontmatter 字段源码位置
     * @param diagnostics 解析阶段产生的结构化诊断
     */
    public SkillDocument(String rawContent, Map<String, Object> frontmatter, String markdownBody,
                         Map<String, SkillSourceLocation> frontmatterLocations,
                         List<SkillValidationIssue> diagnostics) {
        this.rawContent = rawContent;
        this.frontmatter = new SkillMetadata(frontmatter);
        this.markdownBody = markdownBody == null ? "" : markdownBody;
        this.frontmatterLocations = frontmatterLocations == null
                ? new LinkedHashMap<>() : new LinkedHashMap<>(frontmatterLocations);
        this.diagnostics = diagnostics == null ? new ArrayList<>() : new ArrayList<>(diagnostics);
    }

    /**
     * 获取原始完整内容。
     *
     * @return 原始内容
     */
    public String getRawContent() {
        return rawContent;
    }

    /**
     * 设置原始完整内容。
     *
     * @param rawContent 原始内容
     */
    public void setRawContent(String rawContent) {
        this.rawContent = rawContent;
    }

    /**
     * 获取 frontmatter 防御性副本；修改文档请使用 {@link #putFrontmatter(String, Object)}、
     * {@link #removeFrontmatter(String)} 或 {@link #setFrontmatter(SkillMetadata)}。
     *
     * @return frontmatter 有序对象副本
     */
    public SkillMetadata getFrontmatter() {
        return new SkillMetadata(frontmatter.getValues());
    }

    /**
     * 设置 frontmatter 并标记文档已修改。
     *
     * @param frontmatter frontmatter 有序对象
     */
    public void setFrontmatter(SkillMetadata frontmatter) {
        this.frontmatter = frontmatter == null
                ? new SkillMetadata() : new SkillMetadata(frontmatter.getValues());
        this.frontmatterLocations.clear();
        this.modified = true;
    }

    /**
     * 写入一个 frontmatter 字段并标记文档已修改。
     *
     * @param key 字段名
     * @param value 字段值
     */
    public void putFrontmatter(String key, Object value) {
        frontmatter.put(key, value);
        frontmatterLocations.remove(key);
        modified = true;
    }

    /**
     * 删除一个 frontmatter 字段并标记文档已修改。
     *
     * @param key 字段名
     * @return 被删除值的防御性副本
     */
    public Object removeFrontmatter(String key) {
        Object removed = frontmatter.remove(key);
        frontmatterLocations.remove(key);
        modified = true;
        return removed;
    }

    /**
     * 获取顶层 frontmatter 字段的源码位置。
     *
     * @param key frontmatter 字段名
     * @return 源码位置；字段不存在或已被结构化修改时为空
     */
    public SkillSourceLocation getFrontmatterLocation(String key) {
        return key == null ? null : frontmatterLocations.get(key);
    }

    /**
     * 获取顶层 frontmatter 字段源码位置的不可变副本。
     *
     * @return 字段与源码位置映射
     */
    public Map<String, SkillSourceLocation> getFrontmatterLocations() {
        return Collections.unmodifiableMap(new LinkedHashMap<>(frontmatterLocations));
    }

    /**
     * 获取解析阶段结构化诊断的不可变副本。
     *
     * @return 解析诊断
     */
    public List<SkillValidationIssue> getDiagnostics() {
        return Collections.unmodifiableList(new ArrayList<>(diagnostics));
    }

    /**
     * 获取 Markdown 正文。
     *
     * @return Markdown 正文
     */
    public String getMarkdownBody() {
        return markdownBody;
    }

    /**
     * 设置 Markdown 正文并标记文档已修改。
     *
     * @param markdownBody Markdown 正文
     */
    public void setMarkdownBody(String markdownBody) {
        this.markdownBody = markdownBody == null ? "" : markdownBody;
        this.modified = true;
    }

    /**
     * 判断结构化内容是否被修改。
     *
     * @return 已修改时为 true
     */
    public boolean isModified() {
        return modified;
    }

    /**
     * 设置修改标记。
     *
     * @param modified 修改标记
     */
    public void setModified(boolean modified) {
        this.modified = modified;
    }

    /**
     * 渲染完整 SKILL.md；未修改时优先返回原文。
     *
     * @return 完整 SKILL.md
     */
    public String render() {
        if (!modified && rawContent != null) {
            return rawContent;
        }
        return SkillFrontmatter.serialize(frontmatter.getValues(), markdownBody);
    }
}
