/*
 * Copyright (c) 2023-2026 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#import "AceSurfaceView.h"

#import <QuartzCore/QuartzCore.h>
#import <OpenGLES/ES3/gl.h>
#import <OpenGLES/ES3/glext.h>

#import "AceSurfaceCaptureHelper.h"
#import "AceSurfaceHolder.h"
#import "WindowView.h"
#import "StageViewController.h"
#include "base/log/log.h"

@interface AceSurfaceView (){
    BOOL _viewAdded;
    BOOL _isLock;
    CGRect _currentFrame;
    UIInterfaceOrientation  _initialOrientation;
    AceSurfaceCaptureHelper* _surfaceCaptureHelper;

}
@property (nonatomic, assign) int64_t incId;
@property (nonatomic, assign) int32_t instanceId;
@property (nonatomic, copy) IAceOnResourceEvent callback;
@property (nonatomic, strong) NSMutableDictionary<NSString*, IAceOnCallSyncResourceMethod>* callMethodMap;
@property (nonatomic, weak) UIViewController* target;
@property (nonatomic, weak) id<IAceSurface> surfaceDelegate;
@end

@implementation AceSurfaceView

#define SUCCESS @"success"
#define FAIL @"false"

#define PARAM_EQUALS @"#HWJS-=-#"
#define PARAM_BEGIN @"#HWJS-?-#"
#define METHOD @"method"
#define EVENT @"event"
#define SURFACE_FLAG @"surface@"

#define SURFACE_LEFT_KEY @"surfaceLeft"
#define SURFACE_TOP_KEY @"surfaceTop"
#define SURFACE_WIDTH_KEY @"surfaceWidth"
#define SURFACE_HEIGHT_KEY @"surfaceHeight"
#define SURFACE_SET_BOUNDS @"setSurfaceBounds"
#define IS_LOCK @"isLock"

+ (Class)layerClass {
    return [CALayer class];
}

- (instancetype)initWithId:(int64_t)incId callback:(IAceOnResourceEvent)callback
    param:(NSDictionary*)initParam superTarget:(id)target abilityInstanceId:(int32_t)abilityInstanceId
    delegate:(id<IAceSurface>)delegate
{
    if (self = [super init]) {
        LOGI("AceSurfaceView: init instanceId: %{public}lld  incId: %{public}lld", abilityInstanceId,incId);
        self.incId = incId;
        self.instanceId = abilityInstanceId;
        self.callback = callback;
        self.callMethodMap = [[NSMutableDictionary alloc] init];
        self.target = target;
        self.surfaceDelegate = delegate;
        self.autoresizesSubviews = YES;
        __weak AceSurfaceView* weakSelf = self;
        AceSurfaceCaptureConfig* captureConfig = [[AceSurfaceCaptureConfig alloc]
            initWithWidthKey:SURFACE_WIDTH_KEY
            heightKey:SURFACE_HEIGHT_KEY
            logTag:"AceSurfaceView"
            hostLayerBlock:^CALayer* {
                __strong __typeof(weakSelf) strongSelf = weakSelf;
                return strongSelf ? strongSelf.layer : nil;
            }
            drawFallbackBlock:^(CGRect bounds) {
                __strong __typeof(weakSelf) strongSelf = weakSelf;
                if (strongSelf) {
                    [strongSelf drawViewHierarchyInRect:bounds afterScreenUpdates:NO];
                }
            }];
        _surfaceCaptureHelper = [[AceSurfaceCaptureHelper alloc] initWithConfig:captureConfig];

        [self layerCreate];
        [self initEventCallback];
    }
    return self;
}

- (void)initEventCallback
{
    __weak AceSurfaceView* weakSelf = self;
    IAceOnCallSyncResourceMethod callSetSurfaceSize = ^NSString*(NSDictionary* param) {
        if (weakSelf) {
            return [weakSelf setSurfaceBounds:param];
        } else {
            LOGE("AceSurfaceView: setSurfaceBounds fail");
            return FAIL;
        }
    };
    [self.callMethodMap setObject:[callSetSurfaceSize copy]
                           forKey:[self method_hashFormat:@"setSurfaceBounds"]];

    IAceOnCallSyncResourceMethod callAttachNativeWindow = ^NSString*(NSDictionary* param) {
        if (weakSelf) {
            return [weakSelf setAttachNativeWindow:param];
        } else {
            LOGE("AceSurfaceView: callAttachNativeWindow fail");
            return FAIL;
        }
    };
    [self.callMethodMap setObject:[callAttachNativeWindow copy]
                           forKey:[self method_hashFormat:@"attachNativeWindow"]];

    IAceOnCallSyncResourceMethod callSetSurfaceRotation = ^NSString*(NSDictionary* param) {
        if (weakSelf) {
            return [weakSelf setSurfaceRotation:param];
        } else {
            LOGE("AceSurfaceView: callSetSurfaceRotation fail");
            return FAIL;
        }
    };
    [self.callMethodMap setObject:[callSetSurfaceRotation copy]
                           forKey:[self method_hashFormat:@"setSurfaceRotation"]];

    IAceOnCallSyncResourceMethod callsetSurfaceRect = ^NSString*(NSDictionary* param) {
        if (weakSelf) {
            return [weakSelf setSurfaceRect:param];
        } else {
            LOGE("AceSurfaceView: callsetSurfaceRect fail");
            return FAIL;
        }
    };
    [self.callMethodMap setObject:[callsetSurfaceRect copy]
                           forKey:[self method_hashFormat:@"setSurfaceRect"]];

    IAceOnCallSyncResourceMethod callSurfaceCapture = ^NSString*(NSDictionary* param) {
        if (weakSelf) {
            return [weakSelf surfaceCapture:param];
        } else {
            LOGE("AceSurfaceView: callSurfaceCapture fail");
            return FAIL;
        }
    };
    [self.callMethodMap setObject:[callSurfaceCapture copy]
                           forKey:[self method_hashFormat:@"surfaceCapture"]];
}

- (NSString*)surfaceCapture:(NSDictionary*)params
{
    return _surfaceCaptureHelper ? [_surfaceCaptureHelper captureSurface:params bounds:self.bounds] : FAIL;
}

- (void)callSurfaceChange:(CGRect)surfaceRect
{
    if (!self.layer || CGRectEqualToRect(_currentFrame, surfaceRect)) {
        return;
    }
    CGFloat scale = [UIScreen mainScreen].scale;
    CGRect newRect = CGRectMake(surfaceRect.origin.x/scale,
        surfaceRect.origin.y/scale, surfaceRect.size.width/scale, surfaceRect.size.height/scale);
    self.frame = newRect;
    BOOL sizeChanged = !CGSizeEqualToSize(_currentFrame.size, surfaceRect.size);
    _currentFrame = surfaceRect;
    if (!sizeChanged) {
        return;
    }
    NSString *param = [NSString stringWithFormat:@"surfaceWidth=%f&surfaceHeight=%f",
        surfaceRect.size.width, surfaceRect.size.height];
    [self fireCallback:@"onChanged" params:param];
}

- (void)layerCreate
{
    [AceSurfaceHolder addLayer:self.layer withId:self.incId inceId:self.instanceId];
    [self bringSubviewToFront];
}

- (NSDictionary<NSString*, IAceOnCallSyncResourceMethod>*)getCallMethod
{
    return [self.callMethodMap copy];
}

- (NSString*)setSurfaceBounds:(NSDictionary*)params
{
    if (!params[SURFACE_WIDTH_KEY] || !params[SURFACE_HEIGHT_KEY]) {
        return FAIL;
    }
    @try {
        CGFloat surface_x = [params[SURFACE_LEFT_KEY] floatValue];
        CGFloat surface_y = [params[SURFACE_TOP_KEY] floatValue];
        CGFloat surface_width = [params[SURFACE_WIDTH_KEY] floatValue];
        CGFloat surface_height = [params[SURFACE_HEIGHT_KEY] floatValue];
        CGRect surfaceRect = CGRectMake(surface_x, surface_y, surface_width, surface_height);

        if (_viewAdded) {
            [self callSurfaceChange:surfaceRect];
            [self layoutIfNeeded];
        } else {
            _viewAdded = YES;
            UIViewController* superViewController = (UIViewController*)self.target;
            self.frame = superViewController.view.bounds;
            self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
            [self callSurfaceChange:surfaceRect];
            [self bringSubviewToFront];
        }
    } @catch (NSException* exception) {
        LOGE("AceSurfaceView NumberFormatException, setSurfaceSize failed");
        return FAIL;
    }
    return SUCCESS;
}

- (NSString*)setAttachNativeWindow:(NSDictionary*)params
{
    if (!self.surfaceDelegate) {
        LOGE("AceSurfaceView IAceSurface is null");
        return FAIL;
    }
    if (![self.surfaceDelegate respondsToSelector:@selector(attachNaitveSurface:)]) {
        LOGE("AceSurfaceView IAceSurface attachNaitveSurface null");
        return FAIL;
    }
    uintptr_t nativeWindow = [self.surfaceDelegate attachNaitveSurface:self.layer];
    if (nativeWindow == 0) {
        LOGE("AceSurfaceView Surface nativeWindow: null");
        return FAIL;
    }
    NSDictionary * param = @{@"nativeWindow": [NSString stringWithFormat:@"%ld",(long)nativeWindow]};
    return [self convertMapToString:param];
}

- (NSString*)setSurfaceRotation:(NSDictionary*)params
{
    if (!params[IS_LOCK]) {
        return FAIL;
    }
    _isLock = [params[IS_LOCK] boolValue];
    _initialOrientation = [UIApplication sharedApplication].statusBarOrientation;
    return SUCCESS;
}

- (NSString*)setSurfaceRect:(NSDictionary*)params
{
    if (!params[SURFACE_WIDTH_KEY] || !params[SURFACE_HEIGHT_KEY]) {
        return FAIL;
    }
    @try {
        UIScreen *screen = [UIScreen mainScreen];
        CGFloat scale = screen.scale;
        CGFloat x = [params[SURFACE_LEFT_KEY] floatValue];
        CGFloat y = [params[SURFACE_TOP_KEY] floatValue];
        CGFloat width = [params[SURFACE_WIDTH_KEY] floatValue];
        CGFloat height = [params[SURFACE_HEIGHT_KEY] floatValue];
        CGRect surfaceRect = CGRectMake(x / scale, y / scale, width / scale, height / scale);
        CALayer *sublayer = [self.layer.sublayers firstObject];
        if (sublayer) {
            sublayer.frame = surfaceRect;
        }
    } @catch (NSException* exception) {
        LOGE("AceSurfaceView NumberFormatException, setSurfaceSize failed");
        return FAIL;
    }
    return SUCCESS;
}

- (UIView *)findWindowViewInView:(UIView *)view {
    for (UIView *subview in view.subviews) {
        if ([subview isKindOfClass:[WindowView class]]) {
            return subview;
        } 
    }
    return nil;
}

- (void)orientationDidChange {
    if (_isLock == false) {
        return;
    }
    UIInterfaceOrientation currentOrientation = [UIApplication sharedApplication].statusBarOrientation;
    CATransform3D rotationTransform = CATransform3DIdentity;
    switch (_initialOrientation) {
        case UIInterfaceOrientationPortrait:
            if (currentOrientation == UIInterfaceOrientationLandscapeLeft) {
                rotationTransform = CATransform3DMakeRotation(M_PI_2, 0, 0, 1);
            } else if (currentOrientation == UIInterfaceOrientationLandscapeRight) {
                rotationTransform = CATransform3DMakeRotation(-M_PI_2, 0, 0, 1);
            }
            else if (currentOrientation == UIInterfaceOrientationPortraitUpsideDown) {
                rotationTransform = CATransform3DMakeRotation(M_PI, 0, 0, 1);
            }
            break;
        case UIInterfaceOrientationLandscapeLeft:
            if (currentOrientation == UIInterfaceOrientationPortrait) {
                rotationTransform = CATransform3DMakeRotation(-M_PI_2, 0, 0, 1);
            } else if (currentOrientation == UIInterfaceOrientationLandscapeRight) {
                rotationTransform = CATransform3DMakeRotation(M_PI, 0, 0, 1);
            } else if (currentOrientation == UIInterfaceOrientationPortraitUpsideDown) {
                rotationTransform = CATransform3DMakeRotation(M_PI_2, 0, 0, 1);
            }
            break;
        case UIInterfaceOrientationLandscapeRight:
            if (currentOrientation == UIInterfaceOrientationPortrait) {
                rotationTransform = CATransform3DMakeRotation(M_PI_2, 0, 0, 1);
            } else if (currentOrientation == UIInterfaceOrientationLandscapeLeft) {
                rotationTransform = CATransform3DMakeRotation(M_PI, 0, 0, 1);
            } else if (currentOrientation == UIInterfaceOrientationPortraitUpsideDown) {
                rotationTransform = CATransform3DMakeRotation(-M_PI_2, 0, 0, 1);
            }
            break;
        case UIInterfaceOrientationPortraitUpsideDown:
            if (currentOrientation == UIInterfaceOrientationPortrait) {
                rotationTransform = CATransform3DMakeRotation(M_PI, 0, 0, 1);
            } else if (currentOrientation == UIInterfaceOrientationLandscapeLeft) {
                rotationTransform = CATransform3DMakeRotation(-M_PI_2, 0, 0, 1);
            } else if (currentOrientation == UIInterfaceOrientationLandscapeRight) {
                rotationTransform = CATransform3DMakeRotation(M_PI_2, 0, 0, 1);
            }
            break;
        default:
            break;
    }
    CALayer *sublayer = [self.layer.sublayers firstObject];
    if (sublayer) {
        sublayer.transform = rotationTransform;
    }
}

#pragma mark - fireCallback

- (void)fireCallback:(NSString *)method params:(NSString *)params
{
    NSString *method_hash = [NSString stringWithFormat:@"%@%lld%@%@%@%@", 
        SURFACE_FLAG, self.incId, EVENT, PARAM_EQUALS, method, PARAM_BEGIN];
    if (self.callback) {
        self.callback(method_hash, params);
    }
}

- (NSString *)method_hashFormat:(NSString *)method
{
    return [NSString stringWithFormat:@"%@%lld%@%@%@%@", SURFACE_FLAG, self.incId, METHOD, PARAM_EQUALS, method, PARAM_BEGIN];
}

- (long)getResId
{
    return self.incId;
}

- (void)bringSubviewToFront
{
    if (self.target){
        StageViewController* superViewController = (StageViewController*)self.target;
        if (!superViewController){
            return;
        }
        UIView *windowView = [superViewController getWindowView];
        if (!windowView){
            return;
        }
        [windowView.superview insertSubview:self belowSubview:windowView];
    }
}

- (NSString *)convertMapToString:(NSDictionary *)data
{
    NSArray *pairs = [data.allKeys sortedArrayUsingSelector:@selector(compare:)];
    NSMutableString *string = [[NSMutableString alloc] init];
    for (NSString *key in pairs) {
        id value = data[key];
        [string appendFormat:@"%@=%@;", key, value];
    }
    [string deleteCharactersInRange:NSMakeRange(string.length - 1, 1)];
    return string;
}

- (void)releaseObject
{
    @try {
        LOGI("AceSurfaceView releaseObject");
        if (_viewAdded) {
            _viewAdded = false;
        }
        if (self.layer) {
            [AceSurfaceHolder removeLayerWithId:self.incId inceId:self.instanceId];
        }

        if (self.callMethodMap) {
            for (id key in self.callMethodMap) {
                IAceOnCallSyncResourceMethod block = [self.callMethodMap objectForKey:key];
                block = nil;
            }
            [self.callMethodMap removeAllObjects];
            self.callMethodMap = nil;
        }
        self.callback = nil;
        _surfaceCaptureHelper = nil;
        
    } @catch (NSException* exception) {
        LOGE("AceSurfaceView releaseObject failed");
    }
}

- (void)dealloc
{
    LOGI("AceSurfaceView dealloc instanceId: %{public}lld", self.instanceId);
}

@end