//
//  LiveManagementViews.swift
//  suixinkan
//
//  Created by Codex on 2026/6/25.
//

import AVKit
import SwiftUI

/// 直播管理首页，展示直播列表和控制入口。
struct LiveManagementView: View {
    @EnvironmentObject private var accountContext: AccountContext
    @Environment(\.liveAPI) private var liveAPI
    @EnvironmentObject private var toastCenter: ToastCenter
    @Environment(\.globalLoading) private var globalLoading

    @StateObject private var viewModel = LiveManagementViewModel()
    @State private var showAddPage = false

    var body: some View {
        VStack(spacing: 0) {
            summarySection
            ScrollView {
                LazyVStack(spacing: AppMetrics.Spacing.medium) {
                    if viewModel.items.isEmpty {
                        AppContentUnavailableView("暂无直播", systemImage: "dot.radiowaves.left.and.right")
                            .frame(maxWidth: .infinity, minHeight: 280)
                    } else {
                        ForEach(viewModel.items) { item in
                            LiveManagementCard(
                                item: item,
                                onCopyURL: {
                                    UIPasteboard.general.string = item.pushUrl
                                    toastCenter.show("推流地址已复制")
                                },
                                onControl: { Task { await control(item) } },
                                onFinish: { Task { await finish(item) } },
                                detail: {
                                    LiveDetailView(initialDetail: item) {
                                        Task { await reload(showLoading: false) }
                                    }
                                }
                            )
                            .onAppear {
                                guard item.id == viewModel.items.last?.id else { return }
                                Task { await viewModel.loadMore(api: liveAPI, scenicId: accountContext.currentScenic?.id) }
                            }
                        }
                    }

                    if viewModel.loadingMore {
                        ProgressView()
                            .padding(.vertical, AppMetrics.Spacing.small)
                    }
                    Spacer(minLength: 80)
                }
                .padding(.horizontal, AppMetrics.Spacing.pageHorizontal)
                .padding(.vertical, AppMetrics.Spacing.medium)
            }
            Button {
                showAddPage = true
            } label: {
                Label("添加直播", systemImage: "plus.circle.fill")
                    .font(.system(size: AppMetrics.FontSize.body, weight: .semibold))
                    .frame(maxWidth: .infinity)
                    .frame(height: AppMetrics.ControlSize.primaryButtonHeight)
            }
            .buttonStyle(.borderedProminent)
            .padding(.horizontal, AppMetrics.Spacing.pageHorizontal)
            .padding(.vertical, AppMetrics.Spacing.medium)
            .background(.white)
        }
        .background(Color(hex: 0xF5F7FA))
        .navigationTitle("直播管理")
        .navigationBarTitleDisplayMode(.inline)
        .refreshable { await reload(showLoading: false) }
        .task(id: accountContext.currentScenic?.id) {
            await reload(showLoading: viewModel.items.isEmpty)
        }
        .navigationDestination(isPresented: $showAddPage) {
            LiveAddView {
                showAddPage = false
                Task { await reload(showLoading: false) }
            }
        }
    }

    private var summarySection: some View {
        HStack(spacing: AppMetrics.Spacing.small) {
            LiveSummaryChip(title: "总直播", value: "\(viewModel.items.count)", color: AppDesign.primary)
            LiveSummaryChip(title: "进行中", value: "\(viewModel.liveRunningCount)", color: AppDesign.success)
            LiveSummaryChip(title: "已结束", value: "\(viewModel.liveFinishedCount)", color: Color(hex: 0x64748B))
        }
        .padding(AppMetrics.Spacing.medium)
        .background(.white)
    }

    private func reload(showLoading: Bool) async {
        await globalLoading.withOptionalLoading(showLoading && accountContext.currentScenic?.id != nil) {
            await viewModel.reload(api: liveAPI, scenicId: accountContext.currentScenic?.id, showLoading: false)
        }
        if let message = viewModel.errorMessage {
            toastCenter.show(message)
        }
    }

    private func control(_ item: LiveEntity) async {
        do {
            try await viewModel.control(api: liveAPI, item: item, scenicId: accountContext.currentScenic?.id)
        } catch {
            toastCenter.show(error.localizedDescription)
        }
    }

    private func finish(_ item: LiveEntity) async {
        do {
            try await viewModel.finish(api: liveAPI, item: item, scenicId: accountContext.currentScenic?.id)
        } catch {
            toastCenter.show(error.localizedDescription)
        }
    }
}

private struct LiveSummaryChip: View {
    let title: String
    let value: String
    let color: Color

    var body: some View {
        VStack(alignment: .leading, spacing: 4) {
            Text(title)
                .font(.system(size: AppMetrics.FontSize.caption))
                .foregroundStyle(AppDesign.textSecondary)
            Text(value)
                .font(.system(size: AppMetrics.FontSize.body, weight: .bold))
                .foregroundStyle(color)
        }
        .frame(maxWidth: .infinity, alignment: .leading)
        .padding(.horizontal, AppMetrics.Spacing.small)
        .padding(.vertical, AppMetrics.Spacing.small)
        .background(Color(hex: 0xF8FAFC), in: RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.input))
    }
}

private struct LiveManagementCard<Detail: View>: View {
    let item: LiveEntity
    let onCopyURL: () -> Void
    let onControl: () -> Void
    let onFinish: () -> Void
    @ViewBuilder let detail: () -> Detail

    var body: some View {
        VStack(alignment: .leading, spacing: AppMetrics.Spacing.small) {
            HStack(spacing: AppMetrics.Spacing.medium) {
                RemoteImage(urlString: item.coverImg, contentMode: .fill) {
                    RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.input)
                        .fill(Color(hex: 0xE8EEF8))
                        .overlay {
                            Image(systemName: "play.rectangle.fill")
                                .font(.system(size: 28, weight: .semibold))
                                .foregroundStyle(AppDesign.primary.opacity(0.75))
                        }
                }
                .frame(width: 118, height: 72)
                .clipShape(RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.input))

                VStack(alignment: .leading, spacing: 5) {
                    Text(item.title.liveNonEmpty ?? "暂无标题")
                        .font(.system(size: AppMetrics.FontSize.body, weight: .semibold))
                        .foregroundStyle(AppDesign.textPrimary)
                        .lineLimit(1)
                    Text("观看：\(item.viewsCount)")
                        .font(.system(size: AppMetrics.FontSize.caption))
                        .foregroundStyle(AppDesign.textSecondary)
                    Text("时长：\(item.duration.liveDurationText)")
                        .font(.system(size: AppMetrics.FontSize.caption))
                        .foregroundStyle(AppDesign.textSecondary)
                    Text(item.displayStatus)
                        .font(.system(size: AppMetrics.FontSize.caption, weight: .semibold))
                        .foregroundStyle(statusColor)
                }
                Spacer(minLength: 0)
            }

            HStack(spacing: AppMetrics.Spacing.small) {
                NavigationLink(destination: detail) {
                    LiveSmallAction(title: "详情", color: AppDesign.primary)
                }
                .buttonStyle(.plain)
                Button(action: onControl) {
                    LiveSmallAction(title: item.status == 2 ? "暂停" : "开始", color: Color(hex: 0xFF7B00))
                }
                .disabled(item.status == 3)
                Button(action: onFinish) {
                    LiveSmallAction(title: "结束", color: Color(hex: 0xEF4444))
                }
                .disabled(item.status == 3)
                Button(action: onCopyURL) {
                    LiveSmallAction(title: "复制地址", color: AppDesign.success)
                }
                .disabled(item.pushUrl.liveTrimmed.isEmpty)
            }
        }
        .padding(AppMetrics.Spacing.medium)
        .background(.white, in: RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.card))
    }

    private var statusColor: Color {
        switch item.status {
        case 2: AppDesign.success
        case 3: Color(hex: 0x64748B)
        default: AppDesign.primary
        }
    }
}

private struct LiveSmallAction: View {
    let title: String
    let color: Color

    var body: some View {
        Text(title)
            .font(.system(size: AppMetrics.FontSize.caption, weight: .semibold))
            .foregroundStyle(color)
            .frame(maxWidth: .infinity)
            .frame(height: 32)
            .background(color.opacity(0.12), in: RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.input))
    }
}

/// 添加直播页面。
struct LiveAddView: View {
    @EnvironmentObject private var accountContext: AccountContext
    @Environment(\.liveAPI) private var liveAPI
    @EnvironmentObject private var toastCenter: ToastCenter
    @Environment(\.dismiss) private var dismiss

    @State private var title = ""
    @State private var coverURL = ""
    @State private var submitting = false
    let onCreated: () -> Void

    var body: some View {
        VStack(spacing: 0) {
            ScrollView {
                VStack(spacing: AppMetrics.Spacing.medium) {
                    previewSection
                    formSection
                }
                .padding(AppMetrics.Spacing.pageHorizontal)
            }
            Button {
                Task { await submit() }
            } label: {
                HStack {
                    if submitting { ProgressView().tint(.white) }
                    Text(submitting ? "创建中..." : "确认添加")
                }
                .font(.system(size: AppMetrics.FontSize.body, weight: .semibold))
                .frame(maxWidth: .infinity)
                .frame(height: AppMetrics.ControlSize.primaryButtonHeight)
            }
            .buttonStyle(.borderedProminent)
            .disabled(!canSubmit)
            .padding(AppMetrics.Spacing.pageHorizontal)
            .background(.white)
        }
        .background(Color(hex: 0xF5F7FA))
        .navigationTitle("添加直播")
        .navigationBarTitleDisplayMode(.inline)
    }

    private var canSubmit: Bool {
        !submitting && !title.liveTrimmed.isEmpty && coverURL.liveTrimmed.liveIsHTTPURL
    }

    private var previewSection: some View {
        ZStack(alignment: .bottomLeading) {
            if coverURL.liveTrimmed.liveIsHTTPURL {
                RemoteImage(urlString: coverURL.liveTrimmed, contentMode: .fill) {
                    previewPlaceholder
                }
            } else {
                previewPlaceholder
            }
            VStack(alignment: .leading, spacing: AppMetrics.Spacing.xSmall) {
                Text("直播封面")
                    .font(.system(size: AppMetrics.FontSize.caption, weight: .semibold))
                    .foregroundStyle(.white.opacity(0.9))
                Text(title.liveTrimmed.isEmpty ? "输入标题后预览展示效果" : title.liveTrimmed)
                    .font(.system(size: AppMetrics.FontSize.title2, weight: .bold))
                    .foregroundStyle(.white)
                    .lineLimit(2)
            }
            .padding(AppMetrics.Spacing.medium)
            .frame(maxWidth: .infinity, alignment: .leading)
            .background(LinearGradient(colors: [.clear, .black.opacity(0.72)], startPoint: .top, endPoint: .bottom))
        }
        .frame(height: 210)
        .clipShape(RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.card))
    }

    private var previewPlaceholder: some View {
        LinearGradient(colors: [Color(hex: 0x0F274A), AppDesign.primary], startPoint: .topLeading, endPoint: .bottomTrailing)
            .overlay {
                Image(systemName: "play.rectangle.fill")
                    .font(.system(size: 46, weight: .semibold))
                    .foregroundStyle(.white.opacity(0.72))
            }
    }

    private var formSection: some View {
        VStack(alignment: .leading, spacing: AppMetrics.Spacing.medium) {
            Text("直播信息")
                .font(.system(size: AppMetrics.FontSize.title3, weight: .bold))
            TextField("请输入直播标题", text: $title)
                .appInputFieldStyle(cornerRadius: AppMetrics.CornerRadius.input, minHeight: AppMetrics.ControlSize.inputHeight)
            TextField("请输入 http/https 图片地址", text: $coverURL)
                .textInputAutocapitalization(.never)
                .autocorrectionDisabled(true)
                .keyboardType(.URL)
                .appInputFieldStyle(cornerRadius: AppMetrics.CornerRadius.input, minHeight: AppMetrics.ControlSize.inputHeight)
            if !coverURL.liveTrimmed.isEmpty && !coverURL.liveTrimmed.liveIsHTTPURL {
                Text("封面图地址需以 http:// 或 https:// 开头")
                    .font(.system(size: AppMetrics.FontSize.caption))
                    .foregroundStyle(AppDesign.warning)
            }
        }
        .padding(AppMetrics.Spacing.medium)
        .background(.white, in: RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.card))
    }

    private func submit() async {
        guard canSubmit else { return }
        guard let scenicId = accountContext.currentScenic?.id else {
            toastCenter.show("当前账号缺少景区信息")
            return
        }
        submitting = true
        defer { submitting = false }
        do {
            try await liveAPI.liveCreate(LiveCreateRequest(scenicId: String(scenicId), title: title.liveTrimmed, coverImg: coverURL.liveTrimmed))
            onCreated()
            dismiss()
        } catch {
            toastCenter.show(error.localizedDescription)
        }
    }
}

/// 直播详情页面，展示推流信息和控制动作。
struct LiveDetailView: View {
    @Environment(\.liveAPI) private var liveAPI
    @EnvironmentObject private var toastCenter: ToastCenter
    @Environment(\.globalLoading) private var globalLoading
    @StateObject private var viewModel: LiveDetailViewModel
    @StateObject private var playbackViewModel: LivePlaybackViewModel
    @StateObject private var pushReadinessViewModel = LivePushReadinessViewModel()
    @State private var copied = false
    let onChanged: () -> Void

    init(initialDetail: LiveEntity, onChanged: @escaping () -> Void) {
        _viewModel = StateObject(wrappedValue: LiveDetailViewModel(detail: initialDetail))
        _playbackViewModel = StateObject(wrappedValue: LivePlaybackViewModel(live: initialDetail))
        self.onChanged = onChanged
    }

    var body: some View {
        VStack(spacing: 0) {
            ScrollView {
                VStack(spacing: AppMetrics.Spacing.medium) {
                    playbackSection
                    infoSection
                    pushURLSection
                    pushModeSection
                    pushReadinessSection
                    Spacer(minLength: 80)
                }
                .padding(AppMetrics.Spacing.pageHorizontal)
            }
            bottomBar
        }
        .background(Color(hex: 0xF5F7FA))
        .navigationTitle("直播信息")
        .navigationBarTitleDisplayMode(.inline)
        .toolbar {
            ToolbarItem(placement: .topBarTrailing) {
                Button("刷新") {
                    Task { await refresh(showLoading: true) }
                }
                .disabled(viewModel.loading || viewModel.actionInFlight)
            }
        }
        .task {
            pushReadinessViewModel.configure(pushURL: viewModel.detail.pushUrl)
            pushReadinessViewModel.startMonitoring()
            await pushReadinessViewModel.refreshPermissions()
            await refresh(showLoading: false)
        }
        .onDisappear {
            playbackViewModel.release()
            Task { await pushReadinessViewModel.dispose() }
        }
    }

    private var playbackSection: some View {
        ZStack(alignment: .bottomLeading) {
            if let player = playbackViewModel.player, playbackViewModel.playableURL != nil {
                VideoPlayer(player: player)
                    .background(Color.black)
            } else {
                RemoteImage(urlString: viewModel.detail.coverImg, contentMode: .fill) {
                    LinearGradient(colors: [Color(hex: 0x0F274A), AppDesign.primary], startPoint: .topLeading, endPoint: .bottomTrailing)
                        .overlay {
                            Image(systemName: "dot.radiowaves.left.and.right")
                                .font(.system(size: 42, weight: .semibold))
                                .foregroundStyle(.white.opacity(0.72))
                        }
                }
            }
            VStack(alignment: .leading, spacing: AppMetrics.Spacing.small) {
                Text(viewModel.detail.displayStatus)
                    .font(.system(size: AppMetrics.FontSize.caption, weight: .semibold))
                    .foregroundStyle(.white)
                    .padding(.horizontal, AppMetrics.Spacing.small)
                    .frame(height: 26)
                    .background(statusColor.opacity(0.92), in: Capsule())
                Text(viewModel.detail.title.liveNonEmpty ?? "暂无标题")
                    .font(.system(size: AppMetrics.FontSize.title, weight: .bold))
                    .foregroundStyle(.white)
                    .lineLimit(2)
                Text(playbackHint)
                    .font(.system(size: AppMetrics.FontSize.caption, weight: .medium))
                    .foregroundStyle(.white.opacity(0.86))
                    .lineLimit(2)
                HStack(spacing: AppMetrics.Spacing.small) {
                    if playbackViewModel.playableURL != nil {
                        Button {
                            playbackViewModel.isPlaying ? playbackViewModel.pause() : playbackViewModel.play()
                        } label: {
                            Label(playbackViewModel.isPlaying ? "暂停" : "播放", systemImage: playbackViewModel.isPlaying ? "pause.fill" : "play.fill")
                        }
                        Button {
                            playbackViewModel.reload()
                        } label: {
                            Label("重载", systemImage: "arrow.clockwise")
                        }
                    }
                    if let url = playbackViewModel.playableURL {
                        Link(destination: url) {
                            Label("打开", systemImage: "safari")
                        }
                    }
                }
                .font(.system(size: AppMetrics.FontSize.caption, weight: .semibold))
                .buttonStyle(.borderedProminent)
                .tint(.white.opacity(0.22))
            }
            .padding(AppMetrics.Spacing.medium)
            .frame(maxWidth: .infinity, alignment: .leading)
            .background(LinearGradient(colors: [.clear, .black.opacity(0.72)], startPoint: .top, endPoint: .bottom))
        }
        .frame(height: 210)
        .clipShape(RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.card))
    }

    private var playbackHint: String {
        if playbackViewModel.playableURL != nil {
            return "已检测到可播放地址"
        }
        if viewModel.detail.pushUrl.liveTrimmed.lowercased().hasPrefix("rtmp://") {
            return "当前仅有 RTMP 推流地址，系统播放器不可直接播放"
        }
        return "暂无可播放直播地址"
    }

    private var infoSection: some View {
        liveDetailCard("直播信息") {
            LiveInfoRow(title: "标题", value: viewModel.detail.title.liveNonEmpty ?? "--")
            LiveInfoRow(title: "状态", value: viewModel.detail.displayStatus)
            LiveInfoRow(title: "直播时长", value: viewModel.detail.duration.liveDurationText)
            LiveInfoRow(title: "观看人次", value: "\(viewModel.detail.viewsCount)")
        }
    }

    private var pushURLSection: some View {
        liveDetailCard("推流地址") {
            Text("该地址用于 OBS 或第三方推流工具；当前版本不在 App 内采集摄像头/麦克风并推流。")
                .font(.system(size: AppMetrics.FontSize.caption))
                .foregroundStyle(AppDesign.textSecondary)
            Text(viewModel.detail.pushUrl.liveNonEmpty ?? "--")
                .font(.system(size: AppMetrics.FontSize.subheadline))
                .textSelection(.enabled)
                .frame(maxWidth: .infinity, alignment: .leading)
                .padding(AppMetrics.Spacing.medium)
                .background(Color(hex: 0xF8FAFC), in: RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.input))
            Button {
                UIPasteboard.general.string = viewModel.detail.pushUrl
                copied = true
                toastCenter.show("推流地址已复制")
            } label: {
                Label(copied ? "已复制推流地址" : "复制推流地址", systemImage: "doc.on.doc")
                    .frame(maxWidth: .infinity, alignment: .leading)
            }
            .disabled(viewModel.detail.pushUrl.liveTrimmed.isEmpty)
        }
    }

    private var pushModeSection: some View {
        liveDetailCard("推流模式") {
            HStack(spacing: AppMetrics.Spacing.small) {
                pushModeButton("清晰度优先", mode: 1)
                pushModeButton("流畅度优先", mode: 2)
            }
        }
    }

    private var pushReadinessSection: some View {
        liveDetailCard("推流诊断") {
            LiveInfoRow(title: "相机权限", value: pushReadinessViewModel.cameraPermission.displayText)
            LiveInfoRow(title: "麦克风权限", value: pushReadinessViewModel.microphonePermission.displayText)
            LiveInfoRow(title: "网络状态", value: pushReadinessViewModel.networkState.displayText)
            LiveInfoRow(title: "推流 SDK", value: pushReadinessViewModel.adapterName)
            LiveInfoRow(title: "SDK 状态", value: pushReadinessViewModel.sdkStatusText)
            Text("此处仅做权限、网络和 SDK 接入状态诊断；开始、暂停、结束仍只控制 manual-live 业务状态。")
                .font(.system(size: AppMetrics.FontSize.caption))
                .foregroundStyle(AppDesign.textSecondary)
            if let message = pushReadinessViewModel.errorMessage {
                Text(message)
                    .font(.system(size: AppMetrics.FontSize.caption))
                    .foregroundStyle(Color(hex: 0xEF4444))
            }
            HStack(spacing: AppMetrics.Spacing.small) {
                Button {
                    Task { await pushReadinessViewModel.refreshPermissions() }
                } label: {
                    Label("重新检查", systemImage: "checkmark.shield")
                        .frame(maxWidth: .infinity)
                }
                .buttonStyle(.bordered)
                Button {
                    diagnosePush()
                } label: {
                    Label("检查 SDK", systemImage: "antenna.radiowaves.left.and.right")
                        .frame(maxWidth: .infinity)
                }
                .buttonStyle(.borderedProminent)
            }
        }
    }

    private var bottomBar: some View {
        HStack(spacing: AppMetrics.Spacing.medium) {
            Button {
                Task { await control() }
            } label: {
                Text(viewModel.detail.status == 2 ? "暂停直播" : "开始直播")
                    .frame(maxWidth: .infinity)
                    .frame(height: AppMetrics.ControlSize.primaryButtonHeight)
            }
            .buttonStyle(.borderedProminent)
            .disabled(viewModel.detail.status == 3 || viewModel.actionInFlight)

            Button(role: .destructive) {
                Task { await finish() }
            } label: {
                Text("结束直播")
                    .frame(maxWidth: .infinity)
                    .frame(height: AppMetrics.ControlSize.primaryButtonHeight)
            }
            .buttonStyle(.bordered)
            .disabled(viewModel.detail.status == 3 || viewModel.actionInFlight)
        }
        .padding(AppMetrics.Spacing.pageHorizontal)
        .background(.white)
    }

    private var statusColor: Color {
        switch viewModel.detail.status {
        case 2: AppDesign.success
        case 3: Color(hex: 0x64748B)
        default: AppDesign.primary
        }
    }

    private func liveDetailCard<Content: View>(_ title: String, @ViewBuilder content: () -> Content) -> some View {
        VStack(alignment: .leading, spacing: AppMetrics.Spacing.medium) {
            Text(title)
                .font(.system(size: AppMetrics.FontSize.title3, weight: .bold))
                .foregroundStyle(AppDesign.textPrimary)
            content()
        }
        .padding(AppMetrics.Spacing.medium)
        .frame(maxWidth: .infinity, alignment: .leading)
        .background(.white, in: RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.card))
    }

    private func pushModeButton(_ title: String, mode: Int) -> some View {
        Button {
            Task { await setPushMode(mode) }
        } label: {
            Text(title)
                .font(.system(size: AppMetrics.FontSize.subheadline, weight: .semibold))
                .foregroundStyle(viewModel.detail.manualPushMode == mode ? .white : AppDesign.textSecondary)
                .frame(maxWidth: .infinity)
                .frame(height: 46)
                .background(viewModel.detail.manualPushMode == mode ? AppDesign.primary : Color(hex: 0xEEF2F7), in: RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.input))
        }
        .disabled(viewModel.actionInFlight || viewModel.detail.manualPushMode == mode)
        .buttonStyle(.plain)
    }

    private func refresh(showLoading: Bool) async {
        await globalLoading.withOptionalLoading(showLoading) {
            await viewModel.refresh(api: liveAPI, showLoading: false)
        }
        syncMediaState()
        if let message = viewModel.errorMessage {
            toastCenter.show(message)
        }
    }

    private func control() async {
        do {
            try await viewModel.control(api: liveAPI)
            onChanged()
        } catch {
            toastCenter.show(error.localizedDescription)
        }
    }

    private func finish() async {
        do {
            try await viewModel.finish(api: liveAPI)
            onChanged()
        } catch {
            toastCenter.show(error.localizedDescription)
        }
    }

    private func setPushMode(_ mode: Int) async {
        do {
            try await viewModel.setPushMode(api: liveAPI, mode: mode)
            onChanged()
        } catch {
            toastCenter.show(error.localizedDescription)
        }
    }

    private func diagnosePush() {
        pushReadinessViewModel.configure(pushURL: viewModel.detail.pushUrl)
        do {
            try pushReadinessViewModel.runDiagnostics()
            toastCenter.show("推流诊断通过")
        } catch {
            toastCenter.show(error.localizedDescription)
        }
    }

    private func syncMediaState() {
        playbackViewModel.load(live: viewModel.detail)
        pushReadinessViewModel.configure(pushURL: viewModel.detail.pushUrl)
    }
}

private struct LiveInfoRow: View {
    let title: String
    let value: String

    var body: some View {
        HStack(alignment: .top, spacing: AppMetrics.Spacing.medium) {
            Text(title)
                .foregroundStyle(AppDesign.textSecondary)
                .frame(width: 72, alignment: .leading)
            Text(value)
                .foregroundStyle(AppDesign.textPrimary)
                .multilineTextAlignment(.trailing)
                .frame(maxWidth: .infinity, alignment: .trailing)
        }
        .font(.system(size: AppMetrics.FontSize.subheadline))
    }
}

private extension String {
    var liveIsHTTPURL: Bool {
        let lower = liveTrimmed.lowercased()
        return lower.hasPrefix("http://") || lower.hasPrefix("https://")
    }
}
