/*
 * Copyright (c) 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 * as arkts from '@koalaui/libarkts';

import { DecoratorNames, StateManagementTypes } from '../../common/predefines';
import {
    checkIsPropertyCanBeNonNull,
    generateThisBacking,
} from './utils';
import {
    BasePropertyTranslator,
    InnerClassPropertyCachedTranslator,
    InnerClassPropertyTypes,
    PropertyCachedTranslator,
    PropertyCachedTranslatorOptions,
} from './base';
import { factory } from './factory';
import { CustomComponentInnerClassPropertyInfo } from '../../collectors/ui-collectors/records';
import { getValueInObjectAnnotation } from '../utils';

function getCustomEnvKey(property: arkts.ClassProperty): arkts.Expression | undefined {
    const annotations: readonly arkts.AnnotationUsage[] = property.annotations;
    for (const anno of annotations) {
        if (
            anno.expr &&
            arkts.isIdentifier(anno.expr) &&
            anno.expr.name === DecoratorNames.CUSTOM_ENV
        ) {
            const envKeyExpr = getValueInObjectAnnotation(anno, DecoratorNames.CUSTOM_ENV, 'value');
            if (envKeyExpr && arkts.isStringLiteral(envKeyExpr)) {
                return arkts.factory.createIdentifier(envKeyExpr.str);
            }
            return undefined;
        }
    }
    return undefined;
}

function initializeStructWithCustomEnvProperty(
    this: BasePropertyTranslator,
    newName: string,
    originalName: string,
    metadata?: arkts.AstNodeCacheValueMetadata
): arkts.Statement | undefined {
    if (!this.stateManagementType || !this.makeType) {
        return undefined;
    }
    const envKey: arkts.Expression | undefined = getCustomEnvKey(this.property);
    if (!envKey) {
        return undefined;
    }
    const args: arkts.Expression[] = [
        envKey,
        arkts.factory.createStringLiteral(originalName),
        this.property.value?.clone() ?? arkts.factory.createUndefinedLiteral(),
    ];
    if (this.initializeOptions?.isWatched) {
        const watchFuncProperty = factory.addWatchFuncProperty('watchFunc', this.property);
        if (watchFuncProperty) {
            args.push(arkts.factory.createObjectExpression([watchFuncProperty]));
        }
    }
    const assign: arkts.AssignmentExpression = arkts.factory.createAssignmentExpression(
        generateThisBacking(newName),
        factory.generateStateMgmtFactoryCall(this.makeType, this.propertyType?.clone(), args, true, metadata),
        arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION
    );
    return arkts.factory.createExpressionStatement(assign);
}

export class CustomEnvCachedTranslator extends PropertyCachedTranslator {
    protected stateManagementType: StateManagementTypes = StateManagementTypes.CUSTOM_ENV_DECORATED;
    protected makeType: StateManagementTypes = StateManagementTypes.MAKE_CUSTOM_ENV;
    protected shouldWrapPropertyType: boolean = true;
    protected hasInitializeStruct: boolean = true;
    protected hasUpdateStruct: boolean = false;
    protected hasToRecord: boolean = false;
    protected hasField: boolean = true;
    protected hasGetter: boolean = true;
    protected hasSetter: boolean = false;

    constructor(options: PropertyCachedTranslatorOptions) {
        super(options);
        const isWatched = this.propertyInfo.annotationInfo?.hasWatch;
        this.initializeOptions = {
            shouldCheckNonNull: false,
            isWatched
        };
        this.initializeOptions.canDefinitelyBeNonNull = checkIsPropertyCanBeNonNull(
            this.property,
            this.initializeOptions
        );
    }

    initializeStruct(
        newName: string,
        originalName: string,
        metadata?: arkts.AstNodeCacheValueMetadata
    ): arkts.Statement | undefined {
        return initializeStructWithCustomEnvProperty.bind(this)(newName, originalName, metadata);
    }
}

export class CustomEnvCachedInnerClassTranslator<
    T extends InnerClassPropertyTypes,
> extends InnerClassPropertyCachedTranslator<T> {
    protected decorator: DecoratorNames = DecoratorNames.CUSTOM_ENV;

    static canBeTranslated(
        node: arkts.AstNode,
        metadata?: CustomComponentInnerClassPropertyInfo
    ): node is InnerClassPropertyTypes {
        return !!metadata?.name?.startsWith(StateManagementTypes.BACKING) && !!metadata.annotationInfo?.hasCustomEnv;
    }
}