//
//  UIImage+DDCategory.m
//  DDCategoryKit_Private
//  Created by DDIsFriend on 2022/7/29.

#import "UIImage+DDCategory.h"
#import <AVFoundation/AVAsset.h>
#import <CoreMedia/CoreMedia.h>
#import <AVFoundation/AVFoundation.h>

DDWaterMarkInfoName const DDWaterMarkInfoText = @"DDWaterMarkInfoText";
DDWaterMarkInfoName const DDWaterMarkInfoAttributes = @"DDWaterMarkInfoAttributes";

DDWaterMarkInfoName const DDWaterMarkLayoutTop = @"DDWaterMarkInfoTop";
DDWaterMarkInfoName const DDWaterMarkLayoutLeft = @"DDWaterMarkLayoutLeft";
DDWaterMarkInfoName const DDWaterMarkLayoutBottom = @"DDWaterMarkLayoutBottom";
DDWaterMarkInfoName const DDWaterMarkLayoutRight = @"DDWaterMarkLayoutRight";

@implementation UIImage (DDCategory)
+ (UIImage *)dd_thumbnailImageForVideo:(NSURL *)videoURL{
     AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:videoURL options:nil];
     NSParameterAssert(asset);
     AVAssetImageGenerator *assetImageGenerator =[[AVAssetImageGenerator alloc] initWithAsset:asset];
     assetImageGenerator.appliesPreferredTrackTransform = YES;
     assetImageGenerator.apertureMode =AVAssetImageGeneratorApertureModeEncodedPixels;
 
     CGImageRef thumbnailImageRef = NULL;
//     CFTimeInterval thumbnailImageTime = 1;
     NSError *thumbnailImageGenerationError = nil;
     thumbnailImageRef = [assetImageGenerator copyCGImageAtTime:CMTimeMake(0, 1) actualTime:NULL error:&thumbnailImageGenerationError];

    NSAssert(thumbnailImageRef, @"thumbnailImageGenerationError");
 
     UIImage *thumbnailImage = thumbnailImageRef ? [[UIImage alloc] initWithCGImage:thumbnailImageRef] : nil;
     return thumbnailImage;
 }

- (UIImage *)dd_compressWithQulitySize:(NSInteger)maxLength {
    // Compress by quality
    CGFloat compression = 1;
    NSData *data = UIImageJPEGRepresentation(self, compression);
    if (data.length < maxLength) return self;
    
    CGFloat max = 1;
    CGFloat min = 0;
    for (int i = 0; i < 6; ++i) {
        compression = (max + min) / 2;
        data = UIImageJPEGRepresentation(self, compression);
        if (data.length < maxLength * 0.9) {
            min = compression;
        } else if (data.length > maxLength) {
            max = compression;
        } else {
            break;
        }
    }
    UIImage *resultImage = [UIImage imageWithData:data];

    if (data.length < maxLength) return resultImage;
    
    // Compress by size
    NSUInteger lastDataLength = 0;
    while (data.length > maxLength && data.length != lastDataLength) {
        lastDataLength = data.length;
        CGFloat ratio = (CGFloat)maxLength / data.length;
        CGSize size = CGSizeMake((NSUInteger)(resultImage.size.width * sqrtf(ratio)),
                                 (NSUInteger)(resultImage.size.height * sqrtf(ratio))); // Use NSUInteger to prevent white blank
        UIGraphicsBeginImageContext(size);
        [resultImage drawInRect:CGRectMake(0, 0, size.width, size.height)];
        resultImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        data = UIImageJPEGRepresentation(resultImage, compression);
    }

    return resultImage;
}

- (NSData *)dd_compressedToDataWithQulitySize:(NSInteger)maxLength {
    // Compress by quality
    CGFloat compression = 1;
    NSData *data = UIImageJPEGRepresentation(self, compression);
    if (data.length < maxLength) return data;
    
    CGFloat max = 1;
    CGFloat min = 0;
    for (int i = 0; i < 6; ++i) {
        compression = (max + min) / 2;
        data = UIImageJPEGRepresentation(self, compression);
        if (data.length < maxLength * 0.9) {
            min = compression;
        } else if (data.length > maxLength) {
            max = compression;
        } else {
            break;
        }
    }
    UIImage *resultImage = [UIImage imageWithData:data];
    
    if (data.length < maxLength) return data;
    
    // Compress by size
    NSUInteger lastDataLength = 0;
    while (data.length > maxLength && data.length != lastDataLength) {
        lastDataLength = data.length;
        CGFloat ratio = (CGFloat)maxLength / data.length;
        CGSize size = CGSizeMake((NSUInteger)(resultImage.size.width * sqrtf(ratio)),
                                 (NSUInteger)(resultImage.size.height * sqrtf(ratio))); // Use NSUInteger to prevent white blank
        UIGraphicsBeginImageContext(size);
        [resultImage drawInRect:CGRectMake(0, 0, size.width, size.height)];
        resultImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        data = UIImageJPEGRepresentation(resultImage, compression);
    }
   
    return data;
}

- (UIImage *)dd_addWaterMarkWithInfoArray:(NSArray<NSDictionary<DDWaterMarkInfoName,id> *> *)infoArr{
    UIGraphicsBeginImageContextWithOptions(self.size, NO, [UIScreen mainScreen].scale);
    [self drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)];
    [infoArr enumerateObjectsUsingBlock:^(NSDictionary<DDWaterMarkInfoName,id> * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        
        NSString *text = obj[DDWaterMarkInfoText];
        NSNumber *_Nullable top = obj[DDWaterMarkLayoutTop];
        NSNumber *_Nullable left = obj[DDWaterMarkLayoutLeft];
        NSNumber *_Nullable bottom = obj[DDWaterMarkLayoutBottom];
        NSNumber *_Nullable right = obj[DDWaterMarkLayoutRight];
        NSDictionary<NSAttributedStringKey, id> *attrs = obj[DDWaterMarkInfoAttributes];
        
        CGFloat textMaxWidth = self.size.width;
        CGFloat textMaxHeight = self.size.height;
        
        if (left != nil && right != nil) {
            textMaxWidth = self.size.width - left.floatValue - right.floatValue;
        }else if (left != nil && right == nil){
            textMaxWidth = self.size.width - left.floatValue;
        }else if (left == nil && right != nil){
            textMaxWidth = self.size.width - right.floatValue;
        }else{
           // default
        }
        if (top != nil && bottom != nil) {
            textMaxHeight = self.size.height - top.floatValue - bottom.floatValue;
        }else if (top != nil && bottom == nil){
            textMaxHeight = self.size.height - top.floatValue;
        }else if (top == nil && bottom != nil){
            textMaxHeight = self.size.height - bottom.floatValue;
        }else{
            // default
        }
        
        CGFloat width = [text boundingRectWithSize:CGSizeMake(textMaxWidth, textMaxHeight) options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size.width;
        CGFloat height = [text boundingRectWithSize:CGSizeMake(textMaxWidth, textMaxHeight) options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size.height;
        
        CGFloat textX = 0.0;
        CGFloat textY = 0.0;
        
        if (left == nil && right != nil){
            textX = self.size.width - right.floatValue - width;
        }else{
            textX = left.floatValue;
        }
        
        if (top == nil && bottom != nil) {
            textY = self.size.height - bottom.floatValue - height;
        }else{
            textY = top.floatValue;
        }

        [text drawInRect:CGRectMake(textX, textY, width, height) withAttributes:attrs];
    }];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}
@end

@implementation UIImage (LoadWithTrait)
+ (nullable UIImage *)dd_imageWithUserInerfaceStyleLightImage:(UIImage *)lightImage darkImage:(UIImage *)darkImage{
    UIImageAsset *imageAsset = [UIImageAsset new];
    if (@available(iOS 12.0, *)) {
        [imageAsset registerImage:lightImage withTraitCollection:[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleLight]];
        [imageAsset registerImage:darkImage withTraitCollection:[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark]];
        // No mater what user interface style filled here,it will return the user interface style of the current system.
        return [imageAsset imageWithTraitCollection:[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleLight]];
    }
    if (lightImage != nil) return lightImage;
    if (darkImage != nil) return darkImage;
    return nil;
}
@end

@implementation UIImage (LoadWithBundle)
+ (nullable UIImage *)dd_imageNamed:(nonnull NSString *)name bundleName:(nonnull NSString *)bundleName aClass:(nonnull Class)aClass{
    NSString *bundlePath = [[NSBundle bundleForClass:aClass].resourcePath stringByAppendingPathComponent:bundleName];
    
    UIImage *image = [UIImage dd_imageNamed:name bundlePath:bundlePath];

    return image;
}

+ (nullable UIImage *)dd_imageForResource:(nullable NSString *)resource ofType:(nullable NSString *)type bundleName:(nonnull NSString *)bundleName aClass:(nonnull Class)aClass{
    NSString *bundlePath = [[NSBundle bundleForClass:aClass].resourcePath stringByAppendingPathComponent:bundleName];
    
    UIImage *image = [UIImage dd_imageForResource:resource ofType:type bundlePath:bundlePath];

    return image;
}

+ (nullable UIImage *)dd_imageNamed:(nonnull NSString *)name bundlePath:(nonnull NSString *)bundlePath{
    NSString *bundleType = @".bundle";
    if (![bundlePath hasSuffix:bundleType]) {
        bundlePath = [bundlePath stringByAppendingString:bundleType];
    }
    
    NSBundle *sourceBundle = [NSBundle bundleWithPath:bundlePath];
    if (sourceBundle == nil) {
        return nil;
    }
    
    UIImage *image = [UIImage imageNamed:name inBundle:sourceBundle compatibleWithTraitCollection:nil];
    return image;
}

+ (nullable UIImage *)dd_imageForResource:(nullable NSString *)resource ofType:(nullable NSString *)type bundlePath:(nonnull NSString *)bundlePath{
    NSString *bundleType = @".bundle";
    if (![bundlePath hasSuffix:bundleType]) {
        bundlePath = [bundlePath stringByAppendingString:bundleType];
    }
    
    NSBundle *sourceBundle = [NSBundle bundleWithPath:bundlePath];
    if (sourceBundle == nil) {
        return nil;
    }
    
    NSString *imagePath = [sourceBundle pathForResource:resource ofType:type];
    UIImage *image = [UIImage imageWithContentsOfFile:imagePath];

    return image;
}

+ (nullable NSData *)dd_imageGifNamed:(nonnull NSString *)name bundleName:(nonnull NSString *)bundleName aClass:(nonnull Class)aClass{
    NSString *bundlePath = [[NSBundle bundleForClass:aClass].resourcePath stringByAppendingPathComponent:bundleName];
    
    NSData *imageData = [UIImage dd_imageGifNamed:name bundlePath:bundlePath];

    return imageData;
}

+ (nullable NSData *)dd_imageForGifResource:(nullable NSString *)resource ofType:(nullable NSString *)type bundleName:(nonnull NSString *)bundleName aClass:(nonnull Class)aClass{
    NSString *bundlePath = [[NSBundle bundleForClass:aClass].resourcePath stringByAppendingPathComponent:bundleName];
    
    NSData *imageData = [UIImage dd_imageForGifResource:resource ofType:type bundlePath:bundlePath];

    return imageData;
}

+ (nullable NSData *)dd_imageGifNamed:(nonnull NSString *)name bundlePath:(nonnull NSString *)bundlePath{
    NSString *bundleType = @".bundle";
    if (![bundlePath hasSuffix:bundleType]) {
        bundlePath = [bundlePath stringByAppendingString:bundleType];
    }
    
    NSBundle *sourceBundle = [NSBundle bundleWithPath:bundlePath];
    if (sourceBundle == nil) {
        return nil;
    }
    NSString *extension = @".gif";
    if (![name hasSuffix:extension]) {
        name = [name stringByAppendingString:extension];
    }
    NSURL *url = [sourceBundle URLForResource:name withExtension:nil];
    if (url == nil) {
        return nil;
    }
    NSData *imageData = [NSData dataWithContentsOfURL:url];
    return imageData;
}

+ (nullable NSData *)dd_imageForGifResource:(nullable NSString *)resource ofType:(nullable NSString *)type bundlePath:(nonnull NSString *)bundlePath{
    NSString *bundleType = @".bundle";
    if (![bundlePath hasSuffix:bundleType]) {
        bundlePath = [bundlePath stringByAppendingString:bundleType];
    }
    
    NSBundle *sourceBundle = [NSBundle bundleWithPath:bundlePath];
    if (sourceBundle == nil) {
        return nil;
    }
    
    NSURL *url = [sourceBundle URLForResource:resource withExtension:@".gif"];
    NSData *imageData = [NSData dataWithContentsOfURL:url];

    return imageData;
}

+ (instancetype)dd_generateQrcodeImageWithStr:(NSString *)QcodeStr size:(float)size {
    //属于coreImage，可以查看一下相关文档，有很多效果
    CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
    // 滤镜恢复默认设置
    [filter setDefaults];
    //给滤镜添加数据
    NSData *data = [QcodeStr dataUsingEncoding:NSUTF8StringEncoding];
    [filter setValue:data forKeyPath:@"inputMessage"];
    //返回二维码图片
    return [self createHDUIImageFormCIImage:[filter outputImage] withSize:size];
}

//生成高清图片
+ (UIImage *)createHDUIImageFormCIImage:(CIImage *)image withSize:(CGFloat)size {
    CGRect extent = CGRectIntegral(image.extent);
    CGFloat scale = MIN(size/CGRectGetWidth(extent), size/CGRectGetHeight(extent));
    
    // 1.创建bitmap;
    size_t width = CGRectGetWidth(extent) * scale;
    size_t height = CGRectGetHeight(extent) * scale;
    
    CGColorSpaceRef cs = CGColorSpaceCreateDeviceGray();
    CGContextRef bitmapRef =
        CGBitmapContextCreate(nil, width, height, 8, 0, cs, (CGBitmapInfo)kCGImageAlphaNone);
    CIContext *context = [CIContext contextWithOptions:nil];
    CGImageRef bitmapImage = [context createCGImage:image fromRect:extent];
    CGContextSetInterpolationQuality(bitmapRef, kCGInterpolationNone);
    CGContextScaleCTM(bitmapRef, scale, scale);
    CGContextDrawImage(bitmapRef, extent, bitmapImage);
    
    // 2.保存bitmap到图片
    CGImageRef scaledImage = CGBitmapContextCreateImage(bitmapRef);
    CGColorSpaceRelease(cs);
    CGContextRelease(bitmapRef);
    CGImageRelease(bitmapImage);
    UIImage *newImage = [UIImage imageWithCGImage:scaledImage];
    CGImageRelease(scaledImage);
    return newImage;
}

@end

@implementation UIImage (NullSafe)

- (instancetype)dd_nullSafe{
    return (self == nil) ? [[UIImage alloc] init] : self;
}

@end
