import Testing
import Foundation
import SwiftData
@testable import 康康

/// MedicationScanService.parseMedicationsJSON 纯函数单测(JSON 容错与去重)。
struct MedicationScanServiceTests {

    @Test func parsesStandardObject() throws {
        let raw = """
        {"medications":[{"name":"缬沙坦胶囊","strength":"80mg×7粒","usage":""}]}
        """
        let meds = try MedicationScanService.parseMedicationsJSON(raw)
        #expect(meds.count == 1)
        #expect(meds[0].name == "缬沙坦胶囊")
        #expect(meds[0].strength == "80mg×7粒")
        #expect(meds[0].entryText == "缬沙坦胶囊 80mg×7粒")
    }

    @Test func parsesBareArrayWithFence() throws {
        let raw = """
        ```json
        [{"name":"二甲双胍缓释片","strength":"0.5g×30片","usage":"口服,一次1片,一日2次"}]
        ```
        """
        let meds = try MedicationScanService.parseMedicationsJSON(raw)
        #expect(meds.count == 1)
        #expect(meds[0].entryText == "二甲双胍缓释片 0.5g×30片 · 口服,一次1片,一日2次")
    }

    @Test func parsesChineseKeysAndDedupes() throws {
        let raw = """
        {"medications":[
          {"药名":"阿司匹林肠溶片","规格":"100mg","用法":""},
          {"name":"阿司匹林肠溶片","strength":"100mg","usage":""}
        ]}
        """
        let meds = try MedicationScanService.parseMedicationsJSON(raw)
        #expect(meds.count == 1)
    }

    @Test func emptyNameRowsAreDropped() throws {
        let raw = #"{"medications":[{"name":"","strength":"10mg","usage":""}]}"#
        let meds = try MedicationScanService.parseMedicationsJSON(raw)
        #expect(meds.isEmpty)
    }

    @Test func trailingCommaIsRepaired() throws {
        let raw = #"{"medications":[{"name":"氯雷他定片","strength":"10mg×6片","usage":"",},]}"#
        let meds = try MedicationScanService.parseMedicationsJSON(raw)
        #expect(meds.count == 1)
        #expect(meds[0].name == "氯雷他定片")
    }

    @Test func invalidJSONThrows() {
        #expect(throws: (any Error).self) {
            try MedicationScanService.parseMedicationsJSON("识别不出来,抱歉")
        }
    }

    /// 英文药名照原样保留(prompt 已要求英文不翻译);解析层只透传,不应被丢弃。
    @Test func parsesEnglishDrugName() throws {
        let raw = #"{"medications":[{"name":"Amoxicillin","strength":"500mg","usage":"Take one capsule three times daily"}]}"#
        let meds = try MedicationScanService.parseMedicationsJSON(raw)
        #expect(meds.count == 1)
        #expect(meds[0].name == "Amoxicillin")
        #expect(meds[0].entryText == "Amoxicillin 500mg · Take one capsule three times daily")
    }

    /// 通用名 + 商品名合并写法(prompt 约定 "通用名(商品名)")原样透传。
    @Test func parsesGenericWithBrandName() throws {
        let raw = #"{"medications":[{"name":"缬沙坦胶囊(代文)","strength":"80mg×7粒","usage":""}]}"#
        let meds = try MedicationScanService.parseMedicationsJSON(raw)
        #expect(meds.count == 1)
        #expect(meds[0].name == "缬沙坦胶囊(代文)")
    }
}

/// 「用药」日记 → 时间线分类映射(拍药盒入档落库后在「记录」tab 的归类)。
@MainActor
struct MedicationTimelineTests {

    private func makeContext() throws -> ModelContext {
        // DiaryEntry 现关联 Asset(拍药盒原图),schema 必须带上 Asset.self,否则建容器报错。
        let schema = Schema([DiaryEntry.self, Asset.self])
        let config = ModelConfiguration(schema: schema, isStoredInMemoryOnly: true)
        return ModelContext(try ModelContainer(for: schema, configurations: [config]))
    }

    @Test func medicationTaggedDiaryMapsToMedicationKind() throws {
        let ctx = try makeContext()
        let med = DiaryEntry(content: "缬沙坦胶囊 80mg×7粒", tags: [DiaryEntry.medicationTag])
        let plain = DiaryEntry(content: "今天睡得不错")
        ctx.insert(med); ctx.insert(plain)
        try ctx.save()

        let medEntry = TimelineEntry.from(diary: med)
        #expect(medEntry.kind == .medication)
        #expect(medEntry.title == "缬沙坦胶囊 80mg×7粒")

        #expect(TimelineEntry.from(diary: plain).kind == .diary)
    }
}
