import SwiftUI

/// AI 补充句模板(如「症状从 [时间] 开始,」)的一个片段:字面文本或待填占位槽。
enum FillSegment: Equatable {
    case literal(String)
    /// `label` 为方括号内原文(如 "时间" / "活动/休息");
    /// `options` 为可一键填充的短词候选(`/` 分隔且都短时才有,否则空)。
    case slot(label: String, options: [String])
}

/// 把 `fill` 模板解析成有序片段、组装回填好的句子。纯值逻辑,便于复用与单测。
enum DiaryFillTemplate {

    /// 解析模板为有序片段。无方括号时返回单个 `.literal`。
    static func parse(_ template: String) -> [FillSegment] {
        let chars = Array(template)
        var segs: [FillSegment] = []
        var i = 0
        var literalStart = 0
        func flushLiteral(upTo end: Int) {
            if end > literalStart { segs.append(.literal(String(chars[literalStart..<end]))) }
        }
        while i < chars.count {
            if chars[i] == "[",
               let close = (i + 1 ..< chars.count).first(where: { chars[$0] == "]" }) {
                flushLiteral(upTo: i)
                let inner = String(chars[(i + 1)..<close])
                segs.append(.slot(label: inner, options: options(from: inner)))
                i = close + 1
                literalStart = i
            } else {
                i += 1
            }
        }
        flushLiteral(upTo: chars.count)
        return segs
    }

    /// 占位内 `/` 分隔、每段都短(≤5 字)、且 ≥2 段时,视为可点选的快填候选。
    private static func options(from inner: String) -> [String] {
        let tokens = inner.split(separator: "/")
            .map { $0.trimmingCharacters(in: .whitespaces) }
            .filter { !$0.isEmpty }
        guard tokens.count >= 2, tokens.allSatisfy({ $0.count <= 5 }) else { return [] }
        return tokens
    }

    /// 模板里的占位槽数量。
    static func slotCount(_ template: String) -> Int {
        parse(template).reduce(0) { acc, seg in
            if case .slot = seg { return acc + 1 }
            return acc
        }
    }

    /// 用 `values` 填充各槽组装成句:已填用输入值,留空回退为方括号内原文(去方括号,读起来仍自然)。
    static func assemble(_ template: String, values: [String]) -> String {
        var out = ""
        var idx = 0
        for seg in parse(template) {
            switch seg {
            case .literal(let t):
                out += t
            case .slot(let label, _):
                let v = idx < values.count
                    ? values[idx].trimmingCharacters(in: .whitespacesAndNewlines) : ""
                out += v.isEmpty ? label : v
                idx += 1
            }
        }
        return out
    }
}

/// 「采纳即就地填空」面板:每个 `[占位]` 一个输入框 + 快填 chip,顶部实时预览整句,
/// 底部「加入记录 / 取消」。确认时回传**填好的、无方括号**的整句。
struct QuestionFillPanel: View {
    let template: String
    @Binding var values: [String]
    let onCommit: (String) -> Void
    let onCancel: () -> Void

    private var segments: [FillSegment] { DiaryFillTemplate.parse(template) }

    /// 抽出占位槽 + 其在 values 里的下标。
    private var slots: [(index: Int, label: String, options: [String])] {
        var result: [(Int, String, [String])] = []
        var i = 0
        for seg in segments {
            if case let .slot(label, options) = seg {
                result.append((i, label, options))
                i += 1
            }
        }
        return result
    }

    var body: some View {
        VStack(alignment: .leading, spacing: 10) {
            // 实时预览:已填值高亮,未填槽浅色下划线提示。
            previewText
                .font(.tjScaled( 13))
                .fixedSize(horizontal: false, vertical: true)
                .frame(maxWidth: .infinity, alignment: .leading)
                .padding(10)
                .background(
                    RoundedRectangle(cornerRadius: Tj.Radius.sm, style: .continuous)
                        .fill(Tj.Palette.sand2)
                )

            ForEach(slots, id: \.index) { slot in
                slotEditor(index: slot.index, label: slot.label, options: slot.options)
            }

            HStack(spacing: 8) {
                Button(action: onCancel) {
                    Text("取消")
                        .font(.tjScaled( 13, weight: .semibold))
                        .foregroundStyle(Tj.Palette.text2)
                        .frame(maxWidth: .infinity)
                        .padding(.vertical, 9)
                        .background(
                            RoundedRectangle(cornerRadius: Tj.Radius.sm, style: .continuous)
                                .strokeBorder(Tj.Palette.line, lineWidth: 1)
                        )
                        // 背景仅描边、内部透明:.plain 按钮的命中区会只剩文字本身,
                        // 中间透明区点不到。补 contentShape 让整框可点。
                        .contentShape(Rectangle())
                }
                .buttonStyle(.plain)

                Button {
                    onCommit(DiaryFillTemplate.assemble(template, values: values))
                } label: {
                    HStack(spacing: 5) {
                        Image(systemName: "text.append")
                            .font(.tjScaled( 12, weight: .semibold))
                        Text("加入记录")
                            .font(.tjScaled( 13, weight: .semibold))
                    }
                    .foregroundStyle(Tj.Palette.paper)
                    .frame(maxWidth: .infinity)
                    .padding(.vertical, 9)
                    .background(
                        RoundedRectangle(cornerRadius: Tj.Radius.sm, style: .continuous)
                            .fill(Tj.Palette.ink)
                    )
                }
                .buttonStyle(.plain)
            }
        }
        .padding(.leading, 22)
        .padding(.top, 2)
    }

    // MARK: - 子部件

    /// 预览整句:literal 用正文色,已填值用 brick 加粗,未填槽用浅色下划线。
    private var previewText: Text {
        var result = Text("")
        var idx = 0
        for seg in segments {
            switch seg {
            case .literal(let t):
                result = result + Text(t).foregroundStyle(Tj.Palette.text)
            case .slot(let label, _):
                let v = idx < values.count
                    ? values[idx].trimmingCharacters(in: .whitespacesAndNewlines) : ""
                if v.isEmpty {
                    result = result + Text(label).foregroundStyle(Tj.Palette.text3).underline()
                } else {
                    result = result + Text(v).foregroundStyle(Tj.Palette.brick).fontWeight(.semibold)
                }
                idx += 1
            }
        }
        return result
    }

    private func slotEditor(index: Int, label: String, options: [String]) -> some View {
        VStack(alignment: .leading, spacing: 6) {
            Text(label)
                .font(.tjScaled( 11, weight: .semibold))
                .foregroundStyle(Tj.Palette.text3)

            if !options.isEmpty {
                HStack(spacing: 6) {
                    ForEach(options, id: \.self) { opt in
                        let picked = bindingValue(index) == opt
                        Button { values[index] = opt } label: {
                            Text(opt)
                                .font(.tjScaled( 12, weight: picked ? .semibold : .regular))
                                .foregroundStyle(picked ? Tj.Palette.paper : Tj.Palette.text)
                                .padding(.horizontal, 10)
                                .padding(.vertical, 5)
                                .background(
                                    Capsule().fill(picked ? Tj.Palette.ink : Tj.Palette.paper)
                                )
                                .overlay(
                                    Capsule().strokeBorder(Tj.Palette.line,
                                                           lineWidth: picked ? 0 : 1)
                                )
                        }
                        .buttonStyle(.plain)
                    }
                    Spacer(minLength: 0)
                }
            }

            TextField(String(appLoc: "填写\(label)"), text: binding(index))
                .font(.tjScaled( 13))
                .padding(.horizontal, 12)
                .padding(.vertical, 9)
                .background(
                    RoundedRectangle(cornerRadius: Tj.Radius.sm, style: .continuous)
                        .fill(Tj.Palette.paper)
                )
                .overlay(
                    RoundedRectangle(cornerRadius: Tj.Radius.sm, style: .continuous)
                        .strokeBorder(Tj.Palette.line, lineWidth: 1)
                )
        }
    }

    private func bindingValue(_ i: Int) -> String {
        i < values.count ? values[i] : ""
    }

    private func binding(_ i: Int) -> Binding<String> {
        Binding(
            get: { i < values.count ? values[i] : "" },
            set: { if i < values.count { values[i] = $0 } }
        )
    }
}
