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

import AVKit
import PhotosUI
import SwiftUI
import UniformTypeIdentifiers

/// 直播相册首页，展示相册列表、筛选和上传入口。
struct LiveAlbumView: 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 = LiveAlbumViewModel()
    @State private var showStartPicker = false
    @State private var showEndPicker = false
    @State private var showCreatePage = false
    @State private var deleteTarget: LiveAlbumFolderItem?

    var body: some View {
        VStack(spacing: 0) {
            filterSection
            ScrollView {
                LazyVStack(spacing: AppMetrics.Spacing.medium) {
                    if viewModel.folders.isEmpty {
                        AppContentUnavailableView("暂无素材", systemImage: "photo.stack")
                            .frame(maxWidth: .infinity, minHeight: 300)
                    } else {
                        ForEach(viewModel.folders) { folder in
                            LiveAlbumFolderCard(
                                folder: folder,
                                onDelete: { deleteTarget = folder },
                                preview: { file in
                                    let startIndex = folder.items.firstIndex(of: file) ?? 0
                                    LiveAlbumPreviewView(folderId: folder.id, startIndex: startIndex, summary: folder)
                                }
                            )
                            .onAppear {
                                guard folder.id == viewModel.folders.last?.id else { return }
                                Task { await viewModel.loadMore(api: liveAPI, scenicId: accountContext.currentScenic?.id) }
                            }
                        }
                    }

                    if viewModel.loadingMore {
                        ProgressView()
                    }
                    Spacer(minLength: 80)
                }
                .padding(.horizontal, AppMetrics.Spacing.pageHorizontal)
                .padding(.vertical, AppMetrics.Spacing.medium)
            }
            Button {
                showCreatePage = true
            } label: {
                Label("上传素材", systemImage: "square.and.arrow.up")
                    .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.folders.isEmpty)
        }
        .sheet(isPresented: $showStartPicker) {
            LiveDatePickerSheet(title: "开始时间", initialDate: viewModel.startDate ?? Date()) { date in
                applyStartDate(date)
            }
        }
        .sheet(isPresented: $showEndPicker) {
            LiveDatePickerSheet(title: "结束时间", initialDate: viewModel.endDate ?? Date()) { date in
                applyEndDate(date)
            }
        }
        .navigationDestination(isPresented: $showCreatePage) {
            LiveAlbumCreateView {
                showCreatePage = false
                Task { await reload(showLoading: false) }
            }
        }
        .confirmationDialog("删除相册", isPresented: deleteDialogBinding, presenting: deleteTarget) { folder in
            Button("删除", role: .destructive) {
                Task { await deleteFolder(folder) }
            }
            Button("取消", role: .cancel) {}
        } message: { _ in
            Text("确认删除该相册？删除后不可恢复。")
        }
    }

    private var filterSection: some View {
        HStack(spacing: AppMetrics.Spacing.small) {
            filterButton(title: viewModel.startDate?.liveDayText ?? "开始时间") {
                showStartPicker = true
            }
            filterButton(title: viewModel.endDate?.liveDayText ?? "结束时间") {
                showEndPicker = true
            }
            Button {
                viewModel.clearDateFilters()
                Task { await reload(showLoading: true) }
            } label: {
                Image(systemName: "arrow.counterclockwise")
                    .frame(width: 36, height: 36)
            }
            .buttonStyle(.bordered)
            .accessibilityLabel("重置筛选")
        }
        .padding(AppMetrics.Spacing.medium)
        .background(.white)
    }

    private var deleteDialogBinding: Binding<Bool> {
        Binding(
            get: { deleteTarget != nil },
            set: { if !$0 { deleteTarget = nil } }
        )
    }

    private func filterButton(title: String, action: @escaping () -> Void) -> some View {
        Button(action: action) {
            Label(title, systemImage: "calendar")
                .font(.system(size: AppMetrics.FontSize.caption))
                .lineLimit(1)
                .frame(maxWidth: .infinity)
                .frame(height: 36)
        }
        .buttonStyle(.bordered)
    }

    private func applyStartDate(_ date: Date) {
        do {
            try viewModel.setStartDate(date)
            Task { await reload(showLoading: true) }
        } catch {
            toastCenter.show(error.localizedDescription)
        }
    }

    private func applyEndDate(_ date: Date) {
        do {
            try viewModel.setEndDate(date)
            Task { await reload(showLoading: true) }
        } catch {
            toastCenter.show(error.localizedDescription)
        }
    }

    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 deleteFolder(_ folder: LiveAlbumFolderItem) async {
        do {
            try await viewModel.deleteFolder(api: liveAPI, folderId: folder.id, scenicId: accountContext.currentScenic?.id)
            deleteTarget = nil
            toastCenter.show("相册已删除")
        } catch {
            toastCenter.show(error.localizedDescription)
        }
    }
}

private struct LiveAlbumFolderCard<Preview: View>: View {
    let folder: LiveAlbumFolderItem
    let onDelete: () -> Void
    @ViewBuilder let preview: (LiveAlbumFileItem) -> Preview

    var body: some View {
        VStack(alignment: .leading, spacing: AppMetrics.Spacing.small) {
            HStack {
                VStack(alignment: .leading, spacing: 2) {
                    Text(folder.name.liveNonEmpty ?? "暂无标题")
                        .font(.system(size: AppMetrics.FontSize.body, weight: .semibold))
                    if !folder.creator.liveTrimmed.isEmpty {
                        Text(folder.creator)
                            .font(.system(size: AppMetrics.FontSize.caption))
                            .foregroundStyle(AppDesign.textSecondary)
                    }
                }
                Spacer()
                Button(role: .destructive, action: onDelete) {
                    Image(systemName: "trash")
                        .frame(width: 34, height: 34)
                }
            }

            if folder.items.isEmpty {
                Text("暂无素材")
                    .font(.system(size: AppMetrics.FontSize.subheadline))
                    .foregroundStyle(AppDesign.textSecondary)
                    .frame(maxWidth: .infinity, minHeight: 72)
                    .background(Color(hex: 0xF8FAFC), in: RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.input))
            } else {
                LazyVGrid(columns: [GridItem(.flexible()), GridItem(.flexible())], spacing: AppMetrics.Spacing.small) {
                    ForEach(folder.items) { file in
                        NavigationLink(destination: preview(file)) {
                            LiveAlbumThumb(file: file)
                        }
                        .buttonStyle(.plain)
                    }
                }
            }
        }
        .padding(AppMetrics.Spacing.medium)
        .background(.white, in: RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.card))
    }
}

private struct LiveAlbumThumb: View {
    let file: LiveAlbumFileItem

    var body: some View {
        ZStack(alignment: .bottomTrailing) {
            if file.isVideo && file.coverImg?.liveTrimmed.isEmpty != false {
                RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.input)
                    .fill(Color(hex: 0x111827))
                    .overlay {
                        Image(systemName: "play.circle.fill")
                            .font(.system(size: 30, weight: .semibold))
                            .foregroundStyle(.white)
                    }
            } else {
                RemoteImage(urlString: file.previewURL, contentMode: .fill) {
                    RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.input)
                        .fill(Color(hex: 0xEEF2FF))
                }
            }
            if file.isVideo {
                Image(systemName: "play.circle.fill")
                    .font(.system(size: 18))
                    .foregroundStyle(.white)
                    .padding(6)
            }
        }
        .frame(height: 108)
        .clipShape(RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.input))
    }
}

private struct LiveDatePickerSheet: View {
    @Environment(\.dismiss) private var dismiss
    let title: String
    @State var initialDate: Date
    let onConfirm: (Date) -> Void

    var body: some View {
        NavigationStack {
            DatePicker("", selection: $initialDate, displayedComponents: .date)
                .datePickerStyle(.graphical)
                .padding()
                .navigationTitle(title)
                .toolbar {
                    ToolbarItem(placement: .topBarLeading) {
                        Button("取消") { dismiss() }
                    }
                    ToolbarItem(placement: .topBarTrailing) {
                        Button("确定") {
                            onConfirm(initialDate)
                            dismiss()
                        }
                    }
                }
        }
    }
}

/// 新建直播相册页面，支持选择本地图片/视频并上传。
struct LiveAlbumCreateView: View {
    @EnvironmentObject private var accountContext: AccountContext
    @Environment(\.liveAPI) private var liveAPI
    @Environment(\.ossUploadService) private var uploadService
    @EnvironmentObject private var toastCenter: ToastCenter
    @Environment(\.dismiss) private var dismiss

    @StateObject private var viewModel = LiveAlbumCreateViewModel()
    @State private var pickerItems: [PhotosPickerItem] = []
    let onCreated: () -> Void

    var body: some View {
        VStack(spacing: 0) {
            ScrollView {
                VStack(alignment: .leading, spacing: AppMetrics.Spacing.medium) {
                    TextField("请输入相册名称", text: $viewModel.name)
                        .appInputFieldStyle(cornerRadius: AppMetrics.CornerRadius.input, minHeight: AppMetrics.ControlSize.inputHeight)
                    PhotosPicker(selection: $pickerItems, maxSelectionCount: 20, matching: .any(of: [.images, .videos])) {
                        Label("选择图片或视频", systemImage: "photo.on.rectangle.angled")
                            .frame(maxWidth: .infinity)
                            .frame(height: AppMetrics.ControlSize.primaryButtonHeight)
                    }
                    .buttonStyle(.bordered)
                    localFileGrid
                    if viewModel.submitting {
                        ProgressView(value: Double(viewModel.uploadProgress), total: 100)
                    }
                }
                .padding(AppMetrics.Spacing.pageHorizontal)
            }
            Button {
                Task { await submit() }
            } label: {
                Text(viewModel.submitting ? "提交中..." : "保存相册")
                    .frame(maxWidth: .infinity)
                    .frame(height: AppMetrics.ControlSize.primaryButtonHeight)
            }
            .buttonStyle(.borderedProminent)
            .disabled(viewModel.submitting)
            .padding(AppMetrics.Spacing.pageHorizontal)
            .background(.white)
        }
        .background(Color(hex: 0xF5F7FA))
        .navigationTitle("上传素材")
        .navigationBarTitleDisplayMode(.inline)
        .onChange(of: pickerItems) { newItems in
            Task { await importPickerItems(newItems) }
        }
    }

    @ViewBuilder
    private var localFileGrid: some View {
        if viewModel.localFiles.isEmpty {
            AppContentUnavailableView("未选择素材", systemImage: "photo")
                .frame(maxWidth: .infinity, minHeight: 180)
                .background(.white, in: RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.card))
        } else {
            LazyVGrid(columns: [GridItem(.flexible()), GridItem(.flexible())], spacing: AppMetrics.Spacing.small) {
                ForEach(viewModel.localFiles) { file in
                    ZStack(alignment: .topTrailing) {
                        RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.input)
                            .fill(file.isVideo ? Color(hex: 0x111827) : Color(hex: 0xEEF2FF))
                            .frame(height: 108)
                            .overlay {
                                VStack(spacing: 6) {
                                    Image(systemName: file.isVideo ? "video.fill" : "photo.fill")
                                    Text(file.fileName)
                                        .font(.system(size: AppMetrics.FontSize.caption))
                                        .lineLimit(1)
                                }
                                .foregroundStyle(file.isVideo ? .white : AppDesign.textSecondary)
                                .padding(8)
                            }
                        Button {
                            viewModel.removeLocalFile(id: file.id)
                        } label: {
                            Image(systemName: "xmark.circle.fill")
                                .font(.system(size: 20))
                                .foregroundStyle(Color(hex: 0xEF4444))
                                .padding(6)
                        }
                    }
                }
            }
        }
    }

    private func importPickerItems(_ items: [PhotosPickerItem]) async {
        let files = await LiveAlbumPickerLoader.loadFiles(from: items)
        viewModel.addLocalFiles(files)
        pickerItems = []
    }

    private func submit() async {
        do {
            try await viewModel.submit(scenicId: accountContext.currentScenic?.id, api: liveAPI, uploader: uploadService)
            toastCenter.show("相册已创建")
            onCreated()
            dismiss()
        } catch {
            toastCenter.show(error.localizedDescription)
        }
    }
}

/// 直播相册预览页面。
struct LiveAlbumPreviewView: View {
    @Environment(\.liveAPI) private var liveAPI
    @EnvironmentObject private var toastCenter: ToastCenter
    @Environment(\.dismiss) private var dismiss

    @StateObject private var viewModel: LiveAlbumPreviewViewModel
    @State private var showDeleteConfirm = false

    init(folderId: Int, startIndex: Int, summary: LiveAlbumFolderItem?) {
        _viewModel = StateObject(wrappedValue: LiveAlbumPreviewViewModel(folderId: folderId, startIndex: startIndex, summary: summary))
    }

    var body: some View {
        VStack(spacing: 0) {
            if viewModel.files.isEmpty {
                AppContentUnavailableView("没有可预览的素材", systemImage: "photo")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                    .background(Color.black)
            } else {
                TabView(selection: $viewModel.currentIndex) {
                    ForEach(Array(viewModel.files.enumerated()), id: \.offset) { index, file in
                        LiveAlbumPreviewPage(file: file)
                            .tag(index)
                    }
                }
                .tabViewStyle(.page(indexDisplayMode: .automatic))
                .background(Color.black)
            }
            Button(role: .destructive) {
                showDeleteConfirm = true
            } label: {
                Text("删除素材")
                    .frame(maxWidth: .infinity)
                    .frame(height: AppMetrics.ControlSize.primaryButtonHeight)
            }
            .buttonStyle(.borderedProminent)
            .disabled(viewModel.files.isEmpty)
            .padding(AppMetrics.Spacing.pageHorizontal)
            .background(Color.black)
        }
        .navigationTitle("预览")
        .navigationBarTitleDisplayMode(.inline)
        .toolbarColorScheme(.dark, for: .navigationBar)
        .toolbarBackground(Color.black, for: .navigationBar)
        .toolbarBackground(.visible, for: .navigationBar)
        .task { await viewModel.load(api: liveAPI) }
        .confirmationDialog("删除素材", isPresented: $showDeleteConfirm) {
            Button("删除", role: .destructive) {
                Task { await deleteCurrentFile() }
            }
            Button("取消", role: .cancel) {}
        } message: {
            Text("确认删除该素材？删除后不可恢复。")
        }
    }

    private func deleteCurrentFile() async {
        do {
            try await viewModel.deleteCurrentFile(api: liveAPI)
            toastCenter.show("素材已删除")
        } catch {
            toastCenter.show(error.localizedDescription)
        }
    }
}

private struct LiveAlbumPreviewPage: View {
    let file: LiveAlbumFileItem
    @EnvironmentObject private var toastCenter: ToastCenter
    @StateObject private var playbackViewModel: LivePlaybackViewModel

    init(file: LiveAlbumFileItem) {
        self.file = file
        _playbackViewModel = StateObject(wrappedValue: LivePlaybackViewModel(urlString: file.url))
    }

    var body: some View {
        VStack(spacing: AppMetrics.Spacing.medium) {
            if file.isVideo {
                videoContent
            } else {
                RemoteImage(urlString: file.previewURL, contentMode: .fit) {
                    ProgressView()
                        .tint(.white)
                }
            }
            if file.isVideo {
                if let url = URL(string: file.url) {
                    Link("打开视频地址", destination: url)
                        .foregroundStyle(.white)
                }
                Button("复制视频地址") {
                    UIPasteboard.general.string = file.url
                    toastCenter.show("视频地址已复制")
                }
                .foregroundStyle(.white)
            }
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .padding(AppMetrics.Spacing.medium)
        .background(Color.black)
        .onDisappear {
            playbackViewModel.release()
        }
    }

    @ViewBuilder
    private var videoContent: some View {
        if let player = playbackViewModel.player, playbackViewModel.playableURL != nil {
            VideoPlayer(player: player)
                .aspectRatio(16.0 / 9.0, contentMode: .fit)
                .frame(maxWidth: .infinity)
                .clipShape(RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.card))
        } else if file.coverImg?.liveTrimmed.isEmpty == false {
            RemoteImage(urlString: file.previewURL, contentMode: .fit) {
                ProgressView()
                    .tint(.white)
            }
        } else {
            VStack(spacing: AppMetrics.Spacing.small) {
                Image(systemName: "play.slash.fill")
                    .font(.system(size: 62, weight: .semibold))
                    .foregroundStyle(.white)
                Text("当前视频地址暂不可播放")
                    .font(.system(size: AppMetrics.FontSize.subheadline, weight: .semibold))
                    .foregroundStyle(.white)
            }
        }
    }
}

/// PhotosPicker 数据加载器，把系统选择转换为直播相册待上传文件。
enum LiveAlbumPickerLoader {
    static func loadFiles(from items: [PhotosPickerItem]) async -> [LiveAlbumLocalUploadFile] {
        var files: [LiveAlbumLocalUploadFile] = []
        for item in items {
            guard let data = try? await item.loadTransferable(type: Data.self) else { continue }
            let fileType = item.supportedContentTypes.contains(where: { $0.conforms(to: .movie) }) ? 2 : 1
            let ext = preferredExtension(for: item, fileType: fileType)
            files.append(
                LiveAlbumLocalUploadFile(
                    data: data,
                    fileName: "live_album_\(UUID().uuidString.replacingOccurrences(of: "-", with: "")).\(ext)",
                    fileType: fileType
                )
            )
        }
        return files
    }

    private static func preferredExtension(for item: PhotosPickerItem, fileType: Int) -> String {
        if let type = item.supportedContentTypes.first(where: { fileType == 2 ? $0.conforms(to: .movie) : $0.conforms(to: .image) }),
           let ext = type.preferredFilenameExtension {
            return ext
        }
        return fileType == 2 ? "mp4" : "jpg"
    }
}
