import AVFoundation
import SwiftUI

struct StudyAskChatView: View {
    @ObservedObject var controller: StudyChatController
    var sessionTitle: String = ""
    var showStudyTools: Bool = false
    var canVoiceMessage: Bool = true
    var onCollapse: (() -> Void)?
    var onPrevSentence: (() -> Void)?
    var onCapture: (() -> Void)?
    var onAudioAttach: (() -> Void)?
    var onVideoAttach: (() -> Void)?

    @State private var historyOpen = false
    @State private var hiddenAttachIds: Set<String> = []
    @State private var playingVoiceId: String?
    @State private var voicePlayer: AVAudioPlayer?
    @State private var voiceRecorder = VoiceMessageRecorder()
    @State private var recording = false
    @State private var recordSecs = 0
    @State private var recordTimer: Timer?
    @State private var previewImageItem: ImagePreviewItem?

    private let userBubbleFill = Color(red: 0.91, green: 0.94, blue: 0.996)
    private let userBubbleBorder = Color(red: 0.78, green: 0.84, blue: 0.96)
    private let userBubbleText = Color(red: 0.12, green: 0.23, blue: 0.37)
    private let accentBlue = Color(red: 0.01, green: 0.41, blue: 0.64)

    var body: some View {
        VStack(spacing: 0) {
            sidebarHeader
            historyBar
            messageList
            if let error = controller.error {
                Text(error)
                    .font(.caption)
                    .foregroundStyle(.red)
                    .padding(.horizontal, 12)
                    .padding(.vertical, 4)
            }
            if let hint = controller.ttsHint {
                Text(hint)
                    .font(.caption2)
                    .foregroundStyle(accentBlue)
                    .padding(.horizontal, 12)
            }
            composer
        }
        .background(Color.white)
        .sheet(item: $previewImageItem) { item in
            NavigationStack {
                Image(uiImage: item.image)
                    .resizable()
                    .scaledToFit()
                    .padding()
                    .navigationTitle("图片预览")
                    .navigationBarTitleDisplayMode(.inline)
                    .toolbar {
                        ToolbarItem(placement: .cancellationAction) {
                            Button("关闭") { previewImageItem = nil }
                        }
                    }
            }
        }
        .onDisappear {
            stopRecording(resetHint: false)
        }
    }

    private var sidebarHeader: some View {
        HStack(spacing: 8) {
            Text(sessionTitle.isEmpty ? "AI 对话" : sessionTitle)
                .font(.subheadline.weight(.semibold))
                .lineLimit(1)
                .foregroundStyle(Color(red: 0.06, green: 0.09, blue: 0.16))
            Spacer()
            if onCollapse != nil {
                Button {
                    onCollapse?()
                } label: {
                    Image(systemName: "sidebar.right")
                        .font(.system(size: 15))
                }
                .buttonStyle(.plain)
                .foregroundStyle(Color(red: 0.39, green: 0.45, blue: 0.55))
                .accessibilityLabel("收起侧边栏")
            }
        }
        .padding(.horizontal, 12)
        .padding(.vertical, 10)
        .background(Color(red: 0.97, green: 0.98, blue: 0.99))
        .overlay(alignment: .bottom) {
            Divider()
        }
    }

    private var historyBar: some View {
        ZStack(alignment: .topLeading) {
            HStack(spacing: 4) {
                Button {
                    historyOpen.toggle()
                } label: {
                    Image(systemName: "clock")
                        .font(.system(size: 14))
                        .frame(width: 28, height: 28)
                        .background(historyOpen ? Color.white : Color.clear)
                        .overlay(
                            RoundedRectangle(cornerRadius: 8)
                                .stroke(historyOpen ? Color(red: 0.89, green: 0.91, blue: 0.94) : Color.clear, lineWidth: 1)
                        )
                }
                .buttonStyle(.plain)
                .foregroundStyle(historyOpen ? accentBlue : Color(red: 0.28, green: 0.33, blue: 0.41))
                .accessibilityLabel("历史对话")

                Button {
                    historyOpen = false
                    controller.newThread()
                } label: {
                    Image(systemName: "plus")
                        .font(.system(size: 14))
                        .frame(width: 28, height: 28)
                }
                .buttonStyle(.plain)
                .foregroundStyle(Color(red: 0.28, green: 0.33, blue: 0.41))
                .accessibilityLabel("新对话")

                Spacer()

                Button(role: .destructive) {
                    historyOpen = false
                    controller.clearThread()
                } label: {
                    Image(systemName: "trash")
                        .font(.system(size: 14))
                        .frame(width: 28, height: 28)
                }
                .buttonStyle(.plain)
                .foregroundStyle(Color(red: 0.58, green: 0.64, blue: 0.72))
                .disabled(controller.messages.isEmpty)
                .accessibilityLabel("清空对话")
            }
            .padding(.horizontal, 10)
            .padding(.vertical, 8)
            .background(Color(red: 0.97, green: 0.98, blue: 0.99))
            .overlay(alignment: .bottom) {
                Divider()
            }

            if historyOpen {
                historyPanel
                    .padding(.horizontal, 8)
                    .padding(.top, 44)
                    .zIndex(10)
            }
        }
    }

    private var historyPanel: some View {
        VStack(spacing: 0) {
            if controller.threadSummaries.isEmpty {
                Text("暂无历史对话")
                    .font(.caption)
                    .foregroundStyle(.secondary)
                    .frame(maxWidth: .infinity)
                    .padding(.vertical, 14)
            } else {
                ScrollView {
                    VStack(spacing: 2) {
                        ForEach(controller.threadSummaries) { summary in
                            Button {
                                historyOpen = false
                                controller.selectThread(summary.id)
                            } label: {
                                VStack(alignment: .leading, spacing: 2) {
                                    Text(summary.title ?? summary.preview)
                                        .font(.subheadline)
                                        .foregroundStyle(Color(red: 0.06, green: 0.09, blue: 0.16))
                                        .lineLimit(2)
                                        .multilineTextAlignment(.leading)
                                    Text(historyMeta(summary))
                                        .font(.caption2)
                                        .foregroundStyle(.secondary)
                                }
                                .frame(maxWidth: .infinity, alignment: .leading)
                                .padding(.horizontal, 10)
                                .padding(.vertical, 8)
                                .background(
                                    summary.id == controller.activeThreadId
                                        ? Color(red: 0.88, green: 0.95, blue: 0.996)
                                        : Color.clear
                                )
                                .clipShape(RoundedRectangle(cornerRadius: 8))
                            }
                            .buttonStyle(.plain)
                        }
                    }
                    .padding(6)
                }
                .frame(maxHeight: 280)
            }
        }
        .background(Color.white)
        .clipShape(RoundedRectangle(cornerRadius: 10))
        .shadow(color: Color.black.opacity(0.12), radius: 14, y: 6)
        .overlay(
            RoundedRectangle(cornerRadius: 10)
                .stroke(Color(red: 0.89, green: 0.91, blue: 0.94), lineWidth: 1)
        )
    }

    private var messageList: some View {
        ScrollViewReader { proxy in
            ScrollView {
                LazyVStack(alignment: .leading, spacing: 10) {
                    if controller.messages.isEmpty && !controller.busy && controller.error == nil {
                        Text("发送文字或点麦克风录音提问；可粘贴图片；AI 回复支持朗读与 Markdown")
                            .font(.caption)
                            .foregroundStyle(.secondary)
                            .padding(.vertical, 8)
                    }
                    if controller.featureDisabled {
                        Text("该 AI 功能未在电脑端开启。")
                            .font(.subheadline)
                            .foregroundStyle(.secondary)
                            .padding(.vertical, 8)
                    }
                    ForEach(controller.messages) { msg in
                        messageRow(msg)
                            .id(msg.id)
                    }
                    if controller.busy {
                        ProgressView("思考中…")
                            .font(.caption)
                            .padding(.leading, 4)
                    }
                    Color.clear.frame(height: 1).id("bottom")
                }
                .padding(14)
            }
            .onChange(of: controller.messages.count) { _, _ in
                withAnimation { proxy.scrollTo("bottom", anchor: .bottom) }
            }
            .onChange(of: controller.messages.last?.text) { _, _ in
                proxy.scrollTo("bottom", anchor: .bottom)
            }
        }
    }

    @ViewBuilder
    private func messageRow(_ msg: ChatMessage) -> some View {
        if msg.role == .user && msg.kind == .voice {
            voiceMessageRow(msg)
        } else if msg.role == .user {
            userTextRow(msg)
        } else {
            assistantRow(msg)
        }
    }

    private func voiceMessageRow(_ msg: ChatMessage) -> some View {
        let duration = Int(msg.durationSec ?? 0)
        let width = min(220, 88 + duration * 12)
        return VStack(alignment: .trailing, spacing: 4) {
            HStack {
                Spacer(minLength: 40)
                VStack(alignment: .trailing, spacing: 6) {
                    if let path = msg.imagePath, !hiddenAttachIds.contains(msg.id),
                       let ui = loadAttachmentImage(path) {
                        messageImageChip(id: msg.id, image: ui)
                    }
                    Button {
                        playVoiceMessage(msg)
                    } label: {
                        HStack(spacing: 10) {
                            HStack(alignment: .bottom, spacing: 2) {
                                ForEach([6, 12, 8], id: \.self) { h in
                                    RoundedRectangle(cornerRadius: 1)
                                        .fill(userBubbleText)
                                        .frame(width: 3, height: CGFloat(h))
                                }
                            }
                            Text("\(duration)″")
                                .font(.caption.monospacedDigit())
                        }
                        .padding(.horizontal, 12)
                        .frame(width: CGFloat(width), height: 40)
                        .background(playingVoiceId == msg.id ? Color(red: 0.83, green: 0.89, blue: 0.99) : userBubbleFill)
                        .overlay(
                            RoundedRectangle(cornerRadius: 14)
                                .stroke(userBubbleBorder, lineWidth: 1)
                        )
                        .clipShape(RoundedRectangle(cornerRadius: 14))
                    }
                    .buttonStyle(.plain)
                    .foregroundStyle(userBubbleText)
                }
            }
            if !msg.text.isEmpty {
                Text(ChatHistoryHelper.userDisplayText(msg.text))
                    .font(.caption2)
                    .foregroundStyle(.secondary)
                    .frame(maxWidth: .infinity, alignment: .trailing)
            }
        }
    }

    private func userTextRow(_ msg: ChatMessage) -> some View {
        HStack {
            Spacer(minLength: 40)
            VStack(alignment: .trailing, spacing: 6) {
                if let path = msg.imagePath, !hiddenAttachIds.contains(msg.id),
                   let ui = loadAttachmentImage(path) {
                    messageImageChip(id: msg.id, image: ui)
                }
                let displayText = ChatHistoryHelper.userDisplayText(msg.text)
                if !displayText.isEmpty {
                    Text(MarkdownText.stripForDisplay(displayText))
                        .font(.body)
                        .foregroundStyle(userBubbleText)
                        .padding(.horizontal, 12)
                        .padding(.vertical, 8)
                        .background(userBubbleFill)
                        .overlay(
                            RoundedRectangle(cornerRadius: 14)
                                .stroke(userBubbleBorder, lineWidth: 1)
                        )
                        .clipShape(RoundedRectangle(cornerRadius: 14))
                }
            }
        }
    }

    private func assistantRow(_ msg: ChatMessage) -> some View {
        HStack(alignment: .top, spacing: 6) {
            Text(MarkdownText.stripForDisplay(msg.text))
                .font(.system(size: 13.5))
                .foregroundStyle(Color(red: 0.06, green: 0.09, blue: 0.16))
                .frame(maxWidth: .infinity, alignment: .leading)
            if !msg.text.isEmpty, !controller.busy || msg.id != controller.messages.last?.id {
                Button {
                    controller.speak(message: msg)
                } label: {
                    Image(systemName: controller.speakingMessageId == msg.id ? "speaker.wave.3.fill" : "speaker.wave.2")
                        .font(.system(size: 14))
                        .frame(width: 26, height: 26)
                        .background(
                            controller.speakingMessageId == msg.id
                                ? Color(red: 0.89, green: 0.94, blue: 0.98)
                                : Color.clear
                        )
                        .clipShape(RoundedRectangle(cornerRadius: 6))
                }
                .buttonStyle(.plain)
                .foregroundStyle(Color(red: 0.39, green: 0.45, blue: 0.55))
                .disabled(controller.speakingMessageId == msg.id)
                .accessibilityLabel("朗读")
            }
        }
    }

    private func messageImageChip(id: String, image: UIImage) -> some View {
        ZStack(alignment: .topLeading) {
            Button {
                previewImageItem = ImagePreviewItem(image: image)
            } label: {
                Image(uiImage: image)
                    .resizable()
                    .scaledToFill()
                    .frame(width: 40, height: 40)
                    .clipShape(RoundedRectangle(cornerRadius: 8))
                    .overlay(
                        RoundedRectangle(cornerRadius: 8)
                            .stroke(Color(red: 0.89, green: 0.91, blue: 0.94), lineWidth: 1)
                    )
            }
            .buttonStyle(.plain)
            .accessibilityLabel("查看图片")
            Button {
                hiddenAttachIds.insert(id)
            } label: {
                Text("×")
                    .font(.system(size: 11, weight: .bold))
                    .foregroundStyle(.white)
                    .frame(width: 18, height: 18)
                    .background(Color(red: 0.20, green: 0.25, blue: 0.33))
                    .clipShape(Circle())
            }
            .buttonStyle(.plain)
            .offset(x: -6, y: -6)
        }
    }

    private var composer: some View {
        VStack(spacing: 6) {
            if controller.attachmentImage != nil || controller.attachmentAudio != nil {
                HStack(spacing: 8) {
                    if let img = controller.attachmentImage {
                        composerAttachChip {
                            Image(uiImage: img)
                                .resizable()
                                .scaledToFill()
                        } onRemove: {
                            controller.attachmentImage = nil
                        }
                    }
                    if let clip = controller.attachmentAudio {
                        composerAttachChip {
                            Image(systemName: "speaker.wave.2")
                                .font(.system(size: 16))
                                .foregroundStyle(accentBlue)
                        } onRemove: {
                            controller.attachmentAudio = nil
                        }
                        Text(String(format: "%.1f–%.1fs", clip.start, clip.end))
                            .font(.caption2)
                            .foregroundStyle(.secondary)
                    }
                    Spacer()
                }
            }

            ZStack(alignment: .bottomTrailing) {
                TextField(
                    recording
                        ? "录音中，再点麦克风结束并发送…"
                        : "输入新的消息…（Enter 发送，可粘贴图片）",
                    text: $controller.question,
                    axis: .vertical
                )
                .lineLimit(2...6)
                .font(.system(size: 13))
                .padding(.horizontal, 4)
                .padding(.top, 4)
                .padding(.bottom, 40)
                .disabled(controller.featureDisabled || recording)
                .onSubmit {
                    if controller.canSend { controller.send() }
                }

                composerToolbar
            }
        }
        .padding(10)
        .background(Color(red: 0.97, green: 0.98, blue: 0.99))
        .overlay(
            RoundedRectangle(cornerRadius: 14)
                .stroke(Color(red: 0.89, green: 0.91, blue: 0.94), lineWidth: 1)
        )
        .clipShape(RoundedRectangle(cornerRadius: 14))
        .padding(.horizontal, 10)
        .padding(.bottom, 10)
    }

    private var composerToolbar: some View {
        HStack(spacing: 4) {
            if showStudyTools {
                composerTool("chevron.left", label: "上一句", tint: Color(red: 0.39, green: 0.45, blue: 0.55)) {
                    onPrevSentence?()
                }
                composerTool("headphones", label: "音频片段", tint: accentBlue) {
                    onAudioAttach?()
                }
                composerTool("phone.down", label: "语音通话", tint: .red, enabled: false) { }
                composerTool("video", label: "视频预览", tint: accentBlue) {
                    if let onVideoAttach {
                        onVideoAttach()
                    } else {
                        onCapture?()
                    }
                }
                composerTool("pencil", label: "涂鸦", tint: .orange, enabled: false) { }
                composerTool("photo", label: "截图", tint: accentBlue) {
                    onCapture?()
                }
            }
            if canVoiceMessage {
                Button {
                    Task { await toggleRecording() }
                } label: {
                    HStack(spacing: 4) {
                        Image(systemName: recording ? "stop.fill" : "mic.fill")
                            .font(.system(size: 15))
                        if recording {
                            Text("\(recordSecs)″")
                                .font(.caption.monospacedDigit())
                        }
                    }
                    .frame(minWidth: 32, minHeight: 32)
                    .foregroundStyle(recording ? .red : accentBlue)
                }
                .buttonStyle(.plain)
                .disabled(controller.busy || controller.featureDisabled)
                .accessibilityLabel(recording ? "结束录音并发送" : "语音输入")
            }
            Button {
                controller.send()
            } label: {
                Image(systemName: "arrow.up")
                    .font(.system(size: 14, weight: .bold))
                    .foregroundStyle(.white)
                    .frame(width: 32, height: 32)
                    .background(controller.canSend && !recording ? Color(red: 0.06, green: 0.09, blue: 0.16) : Color(red: 0.06, green: 0.09, blue: 0.16).opacity(0.35))
                    .clipShape(Circle())
            }
            .buttonStyle(.plain)
            .disabled(!controller.canSend || recording)
            .accessibilityLabel("发送")
        }
        .padding(.bottom, 2)
    }

    private func composerTool(
        _ symbol: String,
        label: String,
        tint: Color = Color(red: 0.39, green: 0.45, blue: 0.55),
        enabled: Bool = true,
        action: @escaping () -> Void
    ) -> some View {
        Button(action: action) {
            Image(systemName: symbol)
                .font(.system(size: 15, weight: enabled ? .semibold : .regular))
                .frame(width: 32, height: 32)
                .foregroundStyle(enabled ? tint : tint.opacity(0.35))
        }
        .buttonStyle(.plain)
        .disabled(!enabled || controller.featureDisabled || controller.busy || recording)
        .accessibilityLabel(label)
    }

    private func composerAttachChip<Content: View>(
        @ViewBuilder content: () -> Content,
        onRemove: @escaping () -> Void
    ) -> some View {
        ZStack(alignment: .topLeading) {
            content()
                .frame(width: 40, height: 40)
                .clipShape(RoundedRectangle(cornerRadius: 8))
                .overlay(
                    RoundedRectangle(cornerRadius: 8)
                        .stroke(Color(red: 0.89, green: 0.91, blue: 0.94), lineWidth: 1)
                )
            Button(action: onRemove) {
                Text("×")
                    .font(.system(size: 11, weight: .bold))
                    .foregroundStyle(.white)
                    .frame(width: 18, height: 18)
                    .background(Color(red: 0.20, green: 0.25, blue: 0.33))
                    .clipShape(Circle())
            }
            .buttonStyle(.plain)
            .offset(x: -6, y: -6)
        }
    }

    private func historyMeta(_ summary: ChatThreadSummary) -> String {
        var parts: [String] = []
        if !summary.updatedAt.isEmpty { parts.append(String(summary.updatedAt.prefix(16))) }
        if summary.messageCount > 0 { parts.append("\(summary.messageCount) 条") }
        return parts.joined(separator: " · ")
    }

    private func playVoiceMessage(_ msg: ChatMessage) {
        guard let path = msg.audioPath else { return }
        if playingVoiceId == msg.id {
            voicePlayer?.stop()
            playingVoiceId = nil
            return
        }
        let url = ChatHistoryHelper.attachmentFileURL(for: path)
        guard let player = try? AVAudioPlayer(contentsOf: url) else { return }
        voicePlayer?.stop()
        voicePlayer = player
        playingVoiceId = msg.id
        player.play()
        DispatchQueue.main.asyncAfter(deadline: .now() + player.duration + 0.1) {
            if playingVoiceId == msg.id { playingVoiceId = nil }
        }
    }

    private func loadAttachmentImage(_ path: String) -> UIImage? {
        let url = ChatHistoryHelper.attachmentFileURL(for: path)
        return UIImage(contentsOfFile: url.path)
    }

    private func toggleRecording() async {
        if recording {
            recordTimer?.invalidate()
            recordTimer = nil
            recording = false
            recordSecs = 0
            guard let result = voiceRecorder.stop() else { return }
            controller.sendVoice(
                audioPath: result.path,
                durationSec: result.durationSec,
                transcript: controller.question
            )
            controller.question = ""
            return
        }

        do {
            try await voiceRecorder.start()
            recording = true
            recordSecs = 0
            controller.ttsHint = nil
            recordTimer?.invalidate()
            recordTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
                recordSecs = voiceRecorder.elapsedSeconds
            }
        } catch {
            controller.ttsHint = error.localizedDescription
        }
    }

    private func stopRecording(resetHint: Bool) {
        recordTimer?.invalidate()
        recordTimer = nil
        if recording {
            voiceRecorder.cancel()
            recording = false
            recordSecs = 0
            if resetHint { controller.ttsHint = nil }
        }
    }
}

private struct ImagePreviewItem: Identifiable {
    let id = UUID()
    let image: UIImage
}

private enum MarkdownText {
    static func stripForDisplay(_ text: String) -> String {
        var s = text
        if let regex = try? NSRegularExpression(pattern: "```[\\s\\S]*?```", options: []) {
            s = regex.stringByReplacingMatches(in: s, range: NSRange(s.startIndex..., in: s), withTemplate: "\n[代码块]\n")
        }
        s = s.replacingOccurrences(of: "\\*\\*(.+?)\\*\\*", with: "$1", options: .regularExpression)
        s = s.replacingOccurrences(of: "`([^`]+)`", with: "$1", options: .regularExpression)
        s = s.replacingOccurrences(of: "^#+\\s*", with: "", options: .regularExpression)
        return s
    }
}
