package com.agent.management.service.impl;

import com.agent.management.common.exception.BusinessException;
import com.agent.management.config.ErrorPatternProperties;
import com.agent.management.model.entity.HermesErrorPattern;
import com.agent.management.repository.HermesErrorPatternRepository;
import com.agent.management.service.HermesErrorPatternService;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 错误嗅探模式服务实现。
 *
 * <p>内置默认模式来源：{@code application.yml} 的 {@code app.error-pattern.builtin}，
 * 由 {@link ErrorPatternProperties} 注入；未配置时使用代码内 {@link ErrorPatternProperties#DEFAULT_BUILTINS}。</p>
 *
 * <p>启动时若数据文件不存在或为空，自动写入内置默认模式（{@link #initBuiltInPatterns}）。
 * 用户自定义后不被覆盖。</p>
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class HermesErrorPatternServiceImpl implements HermesErrorPatternService {

    private final HermesErrorPatternRepository repository;
    private final ErrorPatternProperties properties;

    /**
     * 嗅探扫描范围：只检查 finalText 的前 N 个字符。
     *
     * <p>错误描述通常出现在 finalText 开头（AIAgent.run() 把错误作为 final_response 返回），
     * 限制扫描范围可避免对超长正常回复做无效 contains。500 字符覆盖所有已知错误前缀。</p>
     */
    private static final int SCAN_LIMIT = 500;

    /**
     * 启动时初始化内置模式。
     *
     * <p>分两种情况：</p>
     * <ul>
     *   <li>数据文件为空（全新部署）：写入全部 {@link ErrorPatternProperties#getBuiltin()}。</li>
     *   <li>数据文件已有模式（升级部署）：按 {@code name} 增量补齐新增的内置模式，
     *       已有条目（含用户对其的编辑/禁用状态）保持不变。</li>
     * </ul>
     */
    @PostConstruct
    public void initBuiltInPatterns() {
        List<HermesErrorPattern> existing = repository.findAll();
        List<ErrorPatternProperties.BuiltinPattern> source =
                properties.getBuiltin() != null && !properties.getBuiltin().isEmpty()
                        ? properties.getBuiltin()
                        : ErrorPatternProperties.DEFAULT_BUILTINS;

        if (existing.isEmpty()) {
            // 全新部署：写入全部内置
            List<HermesErrorPattern> builtIn = new ArrayList<>(source.size());
            for (ErrorPatternProperties.BuiltinPattern b : source) {
                if (isBlank(b.getName()) || isBlank(b.getPattern())) continue;
                builtIn.add(builtIn(b.getName(), b.getPattern(), b.getDescription()));
            }
            repository.saveAll(builtIn);
            log.info("[HermesErrorPattern] 已写入 {} 条内置默认模式", builtIn.size());
            return;
        }

        // 升级部署：按 name 增量补齐（保留用户对已有内置的编辑/禁用状态）
        Set<String> existingNames = existing.stream()
                .map(HermesErrorPattern::getName)
                .collect(Collectors.toSet());
        List<HermesErrorPattern> toAdd = new ArrayList<>();
        for (ErrorPatternProperties.BuiltinPattern b : source) {
            if (isBlank(b.getName()) || isBlank(b.getPattern())) continue;
            if (existingNames.contains(b.getName())) continue;
            toAdd.add(builtIn(b.getName(), b.getPattern(), b.getDescription()));
        }
        if (toAdd.isEmpty()) {
            log.info("[HermesErrorPattern] 已存在 {} 条模式，无需补齐", existing.size());
        } else {
            repository.saveAll(toAdd);
            log.info("[HermesErrorPattern] 增量补齐 {} 条新增内置模式（原有 {} 条保留）",
                    toAdd.size(), existing.size());
        }
    }

    private static boolean isBlank(String s) {
        return s == null || s.trim().isEmpty();
    }

    private HermesErrorPattern builtIn(String name, String pattern, String description) {
        HermesErrorPattern p = new HermesErrorPattern();
        p.setName(name);
        p.setPattern(pattern);
        p.setDescription(description);
        p.setEnabled(true);
        p.setIsBuiltIn(true);
        p.onCreate();
        return p;
    }

    @Override
    public List<HermesErrorPattern> list() {
        List<HermesErrorPattern> all = new ArrayList<>(repository.findAll());
        // 内置在前，然后按 createdAt 升序
        all.sort(Comparator
                .comparing((HermesErrorPattern p) -> Boolean.TRUE.equals(p.getIsBuiltIn()) ? 0 : 1)
                .thenComparing(p -> p.getCreatedAt() == null ? java.time.LocalDateTime.MAX : p.getCreatedAt()));
        return all;
    }

    @Override
    public HermesErrorPattern create(HermesErrorPattern req) {
        validatePattern(req);
        // 名称唯一
        if (repository.findByName(req.getName()).isPresent()) {
            throw new BusinessException("模式名称已存在: " + req.getName());
        }
        HermesErrorPattern entity = new HermesErrorPattern();
        entity.setName(req.getName());
        entity.setPattern(req.getPattern());
        entity.setDescription(req.getDescription());
        entity.setEnabled(req.getEnabled() == null ? true : req.getEnabled());
        entity.setIsBuiltIn(false);  // 用户新建一律不是内置
        entity.onCreate();
        return repository.save(entity);
    }

    @Override
    public HermesErrorPattern update(Long id, HermesErrorPattern req) {
        HermesErrorPattern existing = repository.findById(id)
                .orElseThrow(() -> new BusinessException("模式不存在: " + id));
        validatePattern(req);
        // 名称冲突（与其他模式重名）
        repository.findByName(req.getName()).ifPresent(other -> {
            if (!other.getId().equals(id)) {
                throw new BusinessException("模式名称已存在: " + req.getName());
            }
        });
        existing.setPattern(req.getPattern());
        existing.setDescription(req.getDescription());
        if (req.getEnabled() != null) {
            existing.setEnabled(req.getEnabled());
        }
        // 内置模式禁止改名（保持内置标识稳定）
        if (!Boolean.TRUE.equals(existing.getIsBuiltIn())) {
            existing.setName(req.getName());
        }
        existing.onUpdate();
        return repository.save(existing);
    }

    @Override
    public void delete(Long id) {
        HermesErrorPattern existing = repository.findById(id)
                .orElseThrow(() -> new BusinessException("模式不存在: " + id));
        if (Boolean.TRUE.equals(existing.getIsBuiltIn())) {
            throw new BusinessException("内置模式不可删除，可改为禁用");
        }
        repository.deleteById(id);
    }

    @Override
    public HermesErrorPattern toggle(Long id) {
        HermesErrorPattern existing = repository.findById(id)
                .orElseThrow(() -> new BusinessException("模式不存在: " + id));
        existing.setEnabled(!Boolean.TRUE.equals(existing.getEnabled()));
        existing.onUpdate();
        return repository.save(existing);
    }

    @Override
    public void resetToDefaults() {
        // 保留内置，删除自定义
        repository.deleteAll(p -> !Boolean.TRUE.equals(p.getIsBuiltIn()));
        // 重启内置状态为启用（避免用户禁用了内置后无法恢复）
        for (HermesErrorPattern p : repository.findAll()) {
            if (Boolean.TRUE.equals(p.getIsBuiltIn()) && !Boolean.TRUE.equals(p.getEnabled())) {
                p.setEnabled(true);
                p.onUpdate();
                repository.save(p);
            }
        }
    }

    @Override
    public ErrorDetectionResult isErrorResponse(String finalText) {
        if (finalText == null || finalText.isBlank()) {
            return ErrorDetectionResult.notError();
        }
        String haystack = finalText.length() > SCAN_LIMIT
                ? finalText.substring(0, SCAN_LIMIT)
                : finalText;
        String haystackNorm = normalize(haystack);
        for (HermesErrorPattern p : repository.findAllByEnabledTrue()) {
            String needle = p.getPattern();
            if (needle == null || needle.isBlank()) continue;
            if (haystackNorm.contains(normalize(needle))) {
                return ErrorDetectionResult.of(p.getName());
            }
        }
        return ErrorDetectionResult.notError();
    }

    /**
     * 归一化文本以宽松匹配。
     *
     * <p>将 {@code -}、{@code _}、任意空白视为等价的单一分隔符（统一替换为单个空格），
     * 再小写化。这样模式 {@code api_error} 即可匹配 {@code API ERROR} / {@code api-error} 等。
     * 但不会与"无分隔符"形式（如 {@code apierror}）等价，避免误报。</p>
     */
    private static String normalize(String s) {
        if (s == null) return "";
        return s.replaceAll("[-_\\s]+", " ").toLowerCase();
    }

    private void validatePattern(HermesErrorPattern req) {
        if (req == null) throw new BusinessException("请求体为空");
        if (req.getName() == null || req.getName().trim().isEmpty()) {
            throw new BusinessException("模式名称不能为空");
        }
        if (req.getPattern() == null || req.getPattern().trim().isEmpty()) {
            throw new BusinessException("匹配模式不能为空");
        }
    }
}
