import Testing
import Foundation
@testable import 康康

/// 写日记 AI 辅助的纯解析函数 `DiaryAssistService.parseQuestions`。
/// 这是「非 JSON 输出」回归的修复重点:解析要对 MNN 的各种畸形输出健壮,
/// 彻底解析不出才返回 nil(由 suggest 重试/报错),解析成功但无问题返回 []。
/// parseQuestions 随 @MainActor struct 隔离,测试整体标 @MainActor。
@MainActor
struct DiaryAssistParseTests {

    @Test func parsesStandardWrappedJSON() {
        let raw = #"{"questions":[{"dim":"起病诱因","q":"什么时候开始的?","fill":"从[时间]开始,"},{"dim":"症状性质","q":"是哪种不适?","fill":"性质是[]"}]}"#
        let qs = DiaryAssistService.parseQuestions(from: raw)
        #expect(qs?.count == 2)
        #expect(qs?.first?.dim == "起病诱因")
    }

    @Test func parsesMarkdownFenced() {
        let raw = """
        ```json
        {"questions":[{"dim":"持续频率","q":"持续多久了?","fill":"已持续[时长]"}]}
        ```
        """
        #expect(DiaryAssistService.parseQuestions(from: raw)?.count == 1)
    }

    @Test func parsesThinkWrapped() {
        let raw = "<think>用户头痛,该问起病诱因</think>{\"questions\":[{\"dim\":\"起病诱因\",\"q\":\"何时开始?\",\"fill\":\"从[时间]\"}]}"
        #expect(DiaryAssistService.parseQuestions(from: raw)?.count == 1)
    }

    @Test func parsesBareArrayWithoutWrapper() {
        // MNN 偶尔漏掉外层 {"questions":…},直接吐数组 —— 必须能兜住
        let raw = #"[{"dim":"加重缓解","q":"做什么会加重?","fill":"[活动]时加重"},{"dim":"生活方式","q":"睡眠如何?","fill":"近期睡眠[]"}]"#
        #expect(DiaryAssistService.parseQuestions(from: raw)?.count == 2)
    }

    @Test func repairsTrailingCommaAndSmartQuotes() {
        // 尾逗号 + 中文弯引号:repairJSON 应修好后正常解析
        let raw = "{“questions”:[{“dim”:“用药过敏”,“q”:“在吃什么药?”,“fill”:“在服[药名],”},]}"
        #expect(DiaryAssistService.parseQuestions(from: raw)?.count == 1)
    }

    @Test func emptyQuestionsArrayReturnsEmptyNotNil() {
        // 合法 JSON 但没有问题:返回 [](调用方报 .empty,不是 .parseFailed)
        let qs = DiaryAssistService.parseQuestions(from: #"{"questions":[]}"#)
        #expect(qs != nil)
        #expect(qs?.isEmpty == true)
    }

    @Test func proseReturnsNil() {
        #expect(DiaryAssistService.parseQuestions(from: "我觉得你可以多问问睡眠情况。") == nil)
    }

    @Test func unterminatedThinkOnlyReturnsNil() {
        // 整段都在思考、没吐 JSON 就被截断:strip 后为空 → nil(交给 suggest 重试)
        #expect(DiaryAssistService.parseQuestions(from: "<think>嗯,用户写了头痛,我应该问") == nil)
    }
}
