import UIKit

// MARK: - PendingAttachment

/// Represents an attachment selected by the user but not yet sent.
/// Used in the attachment preview strip above the compositor.
///
/// Desktop parity: the `attachments` state array in `DialogInput.tsx` before
/// `prepareAttachmentsToSend()` processes and uploads them.
struct PendingAttachment: Identifiable, Sendable {

    /// Random 8-character alphanumeric ID (matches desktop's `generateRandomKey(8)`).
    let id: String

    /// Attachment type — `.image` or `.file` for user-initiated sends.
    let type: AttachmentType

    /// Raw image/file data (pre-compression for images).
    let data: Data

    /// Thumbnail for preview (images only). `nil` for files.
    let thumbnail: UIImage?

    /// Original file name (files only). `nil` for images.
    let fileName: String?

    /// File size in bytes (files only). `nil` for images.
    let fileSize: Int?

    /// Voice preview: "duration::waveform_base64" (voice only).
    var voicePreview: String? = nil

    // MARK: - Factory

    /// Creates a PendingAttachment from a UIImage (compressed to JPEG).
    static func fromImage(_ image: UIImage) -> PendingAttachment {
        let id = generateRandomId()
        // Resize to max 1280px on longest side for mobile optimization
        let resized = resizeImage(image, maxDimension: 1280)
        let data = resized.jpegData(compressionQuality: 0.8) ?? Data()
        let thumbnail = resizeImage(image, maxDimension: 200)

        return PendingAttachment(
            id: id,
            type: .image,
            data: data,
            thumbnail: thumbnail,
            fileName: nil,
            fileSize: nil
        )
    }

    /// Creates a PendingAttachment from file data + metadata.
    static func fromFile(data: Data, fileName: String) -> PendingAttachment {
        return PendingAttachment(
            id: generateRandomId(),
            type: .file,
            data: data,
            thumbnail: nil,
            fileName: fileName,
            fileSize: data.count
        )
    }

    /// Creates a PendingAttachment from a voice recording.
    /// Duration in seconds, waveform is normalized [Float] array (0..1).
    static func fromVoice(data: Data, duration: TimeInterval, waveform: [Float]) -> PendingAttachment {
        // Encode waveform as 5-bit base64 for preview
        let waveformBase64 = MessageVoiceView.encodeWaveform(waveform)
        return PendingAttachment(
            id: generateRandomId(),
            type: .voice,
            data: data,
            thumbnail: nil,
            // Encode duration + waveform in fileName for preview extraction
            fileName: "voice_\(Int(duration))s.m4a",
            fileSize: data.count,
            voicePreview: "\(Int(duration))::\(waveformBase64)"
        )
    }

    // MARK: - Helpers

    /// Generates a random 8-character ID (desktop: `generateRandomKey(8)`).
    private static func generateRandomId() -> String {
        let chars = "abcdefghijklmnopqrstuvwxyz0123456789"
        return String((0..<8).map { _ in chars.randomElement()! })
    }

    /// Resizes image so longest side is at most `maxDimension`.
    private static func resizeImage(_ image: UIImage, maxDimension: CGFloat) -> UIImage {
        let size = image.size
        let maxSide = max(size.width, size.height)
        guard maxSide > maxDimension else { return image }

        let scale = maxDimension / maxSide
        let newSize = CGSize(width: size.width * scale, height: size.height * scale)

        let renderer = UIGraphicsImageRenderer(size: newSize)
        return renderer.image { _ in
            image.draw(in: CGRect(origin: .zero, size: newSize))
        }
    }
}

// MARK: - Constants

extension PendingAttachment {
    /// Desktop parity: `MAX_ATTACHMENTS_IN_MESSAGE = 5`.
    static let maxAttachmentsPerMessage = 5
}
