//
//  UploadImageProcessors.swift
//  suixinkan
//

import Foundation
import UIKit
import UniformTypeIdentifiers

/// 头像图片处理器，负责压缩和规范化用户选择的头像图片。
enum AvatarImageProcessor {
    static let maxPixelLength: CGFloat = 1024
    static let jpegCompressionQuality: CGFloat = 0.82

    /// 处理后的上传图片实体，包含数据、文件名和内容类型。
    struct ProcessedImage: Equatable {
        let data: Data
        let fileName: String
        let contentType: UTType
    }

    /// 将原始图片数据转换为适合头像上传的 JPEG 数据。
    static func process(data: Data, timestamp: TimeInterval = Date().timeIntervalSince1970) throws -> ProcessedImage {
        try UploadImageRenderer.process(
            data: data,
            fileNamePrefix: "avatar",
            maxPixelLength: maxPixelLength,
            jpegCompressionQuality: jpegCompressionQuality,
            timestamp: timestamp
        )
    }
}

/// 实名证件图片处理器，负责压缩和规范化身份证正反面图片。
enum RealNameImageProcessor {
    static let maxPixelLength: CGFloat = 1800
    static let jpegCompressionQuality: CGFloat = 0.88

    /// 将原始图片数据转换为适合实名认证上传的 JPEG 数据。
    static func process(data: Data, side: RealNameImageSide, timestamp: TimeInterval = Date().timeIntervalSince1970) throws -> AvatarImageProcessor.ProcessedImage {
        try UploadImageRenderer.process(
            data: data,
            fileNamePrefix: "real_name_\(side.rawValue)",
            maxPixelLength: maxPixelLength,
            jpegCompressionQuality: jpegCompressionQuality,
            timestamp: timestamp
        )
    }
}

/// 银行卡图片处理器，负责压缩银行卡正反面图片。
enum BankCardImageProcessor {
    static let maxPixelLength: CGFloat = 1800
    static let jpegCompressionQuality: CGFloat = 0.88

    static func process(data: Data, side: BankCardImageSide, timestamp: TimeInterval = Date().timeIntervalSince1970) throws -> AvatarImageProcessor.ProcessedImage {
        try UploadImageRenderer.process(
            data: data,
            fileNamePrefix: "bank_card_\(side.rawValue)",
            maxPixelLength: maxPixelLength,
            jpegCompressionQuality: jpegCompressionQuality,
            timestamp: timestamp
        )
    }
}

/// 实名认证证件图片面向实体，区分人像面和国徽面。
enum RealNameImageSide: String {
    case front
    case back
}

/// 银行卡图片面向实体。
enum BankCardImageSide: String {
    case front
    case back
}

/// 上传图片处理错误实体，表示图片无效或编码失败。
enum UploadImageProcessingError: LocalizedError, Equatable {
    case invalidImage
    case encodingFailed

    var errorDescription: String? {
        switch self {
        case .invalidImage:
            "请选择有效的图片"
        case .encodingFailed:
            "图片处理失败，请重新选择"
        }
    }
}

/// 上传图片渲染器，提供通用图片缩放、铺底和 JPEG 编码能力。
private enum UploadImageRenderer {
    static func process(
        data: Data,
        fileNamePrefix: String,
        maxPixelLength: CGFloat,
        jpegCompressionQuality: CGFloat,
        timestamp: TimeInterval
    ) throws -> AvatarImageProcessor.ProcessedImage {
        guard let image = UIImage(data: data), image.size.width > 0, image.size.height > 0 else {
            throw UploadImageProcessingError.invalidImage
        }

        let normalized = image.normalizedForUpload(maxPixelLength: maxPixelLength)
        guard let jpegData = normalized.jpegData(compressionQuality: jpegCompressionQuality), !jpegData.isEmpty else {
            throw UploadImageProcessingError.encodingFailed
        }

        return AvatarImageProcessor.ProcessedImage(
            data: jpegData,
            fileName: "\(fileNamePrefix)_\(Int(timestamp)).jpg",
            contentType: .jpeg
        )
    }
}

private extension UIImage {
    func normalizedForUpload(maxPixelLength: CGFloat) -> UIImage {
        let longestSide = max(size.width, size.height)
        let scale = min(1, maxPixelLength / longestSide)
        let targetSize = CGSize(
            width: max(1, (size.width * scale).rounded()),
            height: max(1, (size.height * scale).rounded())
        )

        let format = UIGraphicsImageRendererFormat.default()
        format.scale = 1
        format.opaque = true
        let renderer = UIGraphicsImageRenderer(size: targetSize, format: format)
        return renderer.image { context in
            UIColor.white.setFill()
            context.fill(CGRect(origin: .zero, size: targetSize))
            draw(in: CGRect(origin: .zero, size: targetSize))
        }
    }
}
