/*
 * Copyright (c) 2023-2025 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 "AceTextureResourcePlugin.h"
#include "AceXcomponentTextureView.h"
#import "AceTextureHolder.h"
#import "AceTexture.h"
#import "AceTextureDelegate.h"
#import "AcePlatformViewDelegate.h"
#import "IAceSurface.h"
#include "base/log/log.h"

@class UIViewController;

static const NSInteger TEXTURETYPE_PLATFORMVIEW = 0;
static const NSInteger TEXTURETYPE_XCOMPONENT = 1;

@interface AceTextureResourcePlugin()
@property (nonatomic, strong) NSMutableDictionary<NSString*, AceTexture*> *objectMap;
@property (nonatomic, strong) NSMutableDictionary<NSString*, AceXcomponentTextureView*> *textureViewMap;
@property (nonatomic, assign) int32_t instanceId;
@property (nonatomic, weak) UIViewController *target;
@end

@implementation AceTextureResourcePlugin

+ (AceTextureResourcePlugin *)createTexturePluginWithTarget:(UIViewController *)target instanceId:(int32_t)instanceId
{
    return [[AceTextureResourcePlugin alloc] initTextureWithTarget:target instanceId:instanceId];
}

- (instancetype)initTextureWithTarget:(UIViewController *)target instanceId:(int32_t)instanceId
{
    self = [super init:@"texture" version:1];
    if (self) {
        self.objectMap = [NSMutableDictionary dictionary];
        self.textureViewMap = [NSMutableDictionary dictionary];
        self.instanceId = instanceId;
        if (target) {
            self.target = target;
        }
    }
    return self;
}

- (void)addResource:(int64_t)textureId texture:(AceTexture *)texture type:(NSInteger)type
{
    [self.objectMap setObject:texture forKey:[NSString stringWithFormat:@"%lld", textureId]];
    NSDictionary *callMethod = [texture getCallMethod];
    [self registerSyncCallMethod:callMethod];
    // This section is only effective for platform views; it does not apply to other cases.
    if (type == TEXTURETYPE_PLATFORMVIEW) {
        [self.delegate registerSurfaceWithInstanceId:self.instanceId textureId:textureId 
        textureObject:(__bridge void*)texture.videoOutput];
    }
    [AceTextureHolder addTexture:texture withId:textureId inceId:self.instanceId];
}

- (int64_t)create:(NSDictionary<NSString *, NSString *> *)param
{
    int64_t textureId = [self getAtomicId];
    IAceOnResourceEvent callback = [self getEventCallback];
    if (!callback) {
        return -1L;
    }
    NSInteger type = TEXTURETYPE_PLATFORMVIEW;
    if (param && param[@"type"]) {
        type = [param[@"type"] integerValue];
    }
    LOGI("AceTextureCreate type: %{public}ld, paramSize: %{public}lu", type, (unsigned long)param.allKeys.count);
    AceTexture *texture = [[AceTexture alloc] initWithEvents:callback textureId:textureId
    abilityInstanceId:self.instanceId];
    [self addResource:textureId texture:texture type:type];
    if (type == TEXTURETYPE_XCOMPONENT) {
        AceXcomponentTextureView *textureView = [[AceXcomponentTextureView alloc] initWithId:textureId instanceId:self.instanceId
        callback:callback param:param superTarget:self.target viewdelegate:self.platformViewDelegate 
        surfaceDelegate:self.surfaceDelegate];
        [self.textureViewMap setObject:textureView forKey:[NSString stringWithFormat:@"%lld", textureId]];
        NSDictionary * callMethod = [textureView getCallMethod];
        [self registerSyncCallMethod:callMethod];
    }
    return textureId;
}

- (id)getObject:(NSString *)incId
{
    return [self.objectMap objectForKey:incId];
}

- (BOOL)release:(NSString *)incId
{
    LOGI("AceTextResourcePlugin %{public}s release inceId: %{public}s", __func__, [incId UTF8String]);
    AceTexture *texture = [self.objectMap objectForKey:incId];
    AceXcomponentTextureView *textureView = [self.textureViewMap objectForKey:incId];
    if (textureView) {
        [self unregisterSyncCallMethod:[textureView getCallMethod]];
        [textureView releaseObject];
        [self.textureViewMap removeObjectForKey:incId];
        textureView = nil;
    }
    if (texture) {
        [self unregisterSyncCallMethod:[texture getCallMethod]];
        [texture releaseObject];
        [self.objectMap removeObjectForKey:incId];
        [AceTextureHolder removeTextureWithId:[incId intValue] inceId:self.instanceId];
        [self.delegate unregisterSurfaceWithInstanceId:self.instanceId textureId:[incId intValue]];
        texture = nil;
        return YES;
    }
    return NO;
}

- (void)releaseObject
{
    LOGI("AceTextResourcePlugin releaseObjectStart");
    if (self.objectMap) {
        [self.objectMap enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key,
            AceTexture *_Nonnull texture, BOOL * _Nonnull stop) {
            if (texture) {
                [texture releaseObject];
                texture = nil;
            } else {
                LOGE("AceSurfacePlugin releaseObject fail aceSurface is null");
            }
        }];
        [self.objectMap removeAllObjects];
        self.objectMap = nil;
    }
    if (self.textureViewMap) {
        [self.textureViewMap enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key,
            AceXcomponentTextureView *_Nonnull textureView, BOOL * _Nonnull stop) {
            if (textureView) {
                [textureView releaseObject];
                textureView = nil;
            } else {
                LOGE("AceSurfacePlugin releaseObject fail aceSurfaceView is null");
            }
        }];
        [self.textureViewMap removeAllObjects];
        self.textureViewMap = nil;
    }
}

- (void)dealloc
{
    LOGI("AceTextureResourcePlugin dealloc instanceId=%{public}lld", static_cast<long long>(self.instanceId));
}
@end