import ForgejoKit
import SwiftUI

/// Markdown to insert when an attachment is uploaded. Images use embed syntax
/// (`![name](url)`) so they render inline; every other file type (logs, PDFs,
/// archives, and so on) uses link syntax (`[name](url)`) so it appears as a
/// clickable link rather than a broken inline image.
func attachmentMarkdown(for attachment: Attachment) -> String {
    if attachment.isImage {
        "![\(attachment.name)](\(attachment.browserDownloadUrl))"
    } else {
        "[\(attachment.name)](\(attachment.browserDownloadUrl))"
    }
}

struct AttachmentGallery: View {
    let attachments: [Attachment]

    private var imageAttachments: [Attachment] {
        attachments.filter(\.isImage)
    }

    private var fileAttachments: [Attachment] {
        attachments.filter { !$0.isImage }
    }

    var body: some View {
        VStack(alignment: .leading, spacing: 8) {
            if !imageAttachments.isEmpty {
                ScrollView(.horizontal, showsIndicators: false) {
                    HStack(spacing: 8) {
                        ForEach(imageAttachments) { attachment in
                            imageThumb(attachment)
                        }
                    }
                }
                .accessibilityIdentifier("attachment-gallery")
            }

            ForEach(fileAttachments) { attachment in
                fileRow(attachment)
            }
        }
    }

    private func imageThumb(_ attachment: Attachment) -> some View {
        Group {
            if let url = URL(string: attachment.browserDownloadUrl) {
                Link(destination: url) {
                    AsyncImage(url: url) { phase in
                        switch phase {
                        case let .success(image):
                            image
                                .resizable()
                                .scaledToFill()
                        case .failure:
                            brokenImagePlaceholder
                        default:
                            ProgressView()
                                .frame(maxWidth: .infinity, maxHeight: .infinity)
                        }
                    }
                    .frame(width: 120, height: 90)
                    .clipped()
                    .clipShape(RoundedRectangle(cornerRadius: 8))
                }
            }
        }
    }

    private func fileRow(_ attachment: Attachment) -> some View {
        Group {
            if let url = URL(string: attachment.browserDownloadUrl) {
                Link(destination: url) {
                    HStack(spacing: 8) {
                        Image(systemName: "paperclip")
                            .foregroundStyle(.secondary)
                        Text(attachment.name)
                            .font(.subheadline)
                        Spacer()
                        Text(formatFileSize(attachment.size))
                            .font(.caption)
                            .foregroundStyle(.secondary)
                    }
                }
                .tint(.primary)
                .accessibilityIdentifier("attachment-file-row")
            }
        }
    }

    private var brokenImagePlaceholder: some View {
        Image(systemName: "photo.badge.exclamationmark")
            .font(.title2)
            .foregroundStyle(.secondary)
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .background(Color(.tertiarySystemFill))
    }

    private func formatFileSize(_ bytes: Int) -> String {
        let kilobytes = Double(bytes) / 1024
        if kilobytes < 1024 {
            return String(format: "%.1f KB", kilobytes)
        }
        return String(format: "%.1f MB", kilobytes / 1024)
    }
}

#if DEBUG
    #Preview("Images") {
        List {
            Section("Attachments") {
                AttachmentGallery(attachments: [.previewImage, .previewFile])
            }
        }
        .listStyle(.insetGrouped)
    }

    #Preview("Empty") {
        AttachmentGallery(attachments: [])
    }
#endif
