#!/usr/bin/env python3
# coding=UTF-8
# Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
#
# 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.

"""instance manager"""

from yr.common.singleton import Singleton
from yr.object_ref import ObjectRef


@Singleton
class InstanceManager:
    """
    InstanceManager stores class instance
    """

    def __init__(self):
        self.__instance = None
        self.__config = None
        self.__class_code = None
        self.__is_async = False
        self.__code_obj_ref = None
        self.__code_id = None
        self._tensor_map = {}

    @property
    def config(self):
        """get config"""
        return self.__config

    @config.setter
    def config(self, value):
        """save config"""
        self.__config = value

    @property
    def class_code(self):
        """get class code"""
        return self.__class_code

    @class_code.setter
    def class_code(self, code):
        """set class code"""
        self.__class_code = code

    @property
    def is_async(self):
        """get is_async"""
        return self.__is_async

    @is_async.setter
    def is_async(self, is_async):
        """set isAsync code"""
        self.__is_async = is_async

    @property
    def code_id(self):
        """get code_id"""
        return self.__code_id

    def set_code_ref(self, code_id, is_recover):
        """
        code_id: object id of python code
        code_obj_ref: object ref generated by code_id
        To prevent the client that creates a detached instance exiting and causing the object reference of python code
        to be parsed, therefore, an object ref of the python code is held in the instance_manager.
        In addition, if the instance receives a signal like kill -9 and then recover, since the __del__ method of object
        ref has not been executed, the recover instance no need to increase.
        """
        if code_id is None or not isinstance(code_id, str) or len(code_id) == 0:
            return
        self.__code_id = code_id
        if is_recover:
            self.__code_obj_ref = ObjectRef(object_id=code_id, need_incre=False)
        self.__code_obj_ref = ObjectRef(object_id=code_id)

    def init(self, instance=None):
        """"
        save instance
        """
        self.__instance = instance

    def instance(self):
        """"
        get instance
        """
        return self.__instance

    def get_instance_package(self):
        """
        get instance package
        """
        return InstancePackage(self.__instance, self.__class_code, self.__is_async, self.__code_id)

    def init_from_inspackage(self, ins_package):
        """
        save instance from instance package
        """
        self.__instance = ins_package.get_instance()
        self.__class_code = ins_package.get_class_code()
        self.__is_async = ins_package.get_is_async()
        self.set_code_ref(ins_package.get_code_id(), True)

    def store_tensor_in_local(self, tensor, npu_obj_id):
        self._tensor_map[npu_obj_id] = tensor

    def erase_tensors(self, npu_obj_ids):
        if not isinstance(npu_obj_ids, list):
            return
        for npu_id in npu_obj_ids:
            self._tensor_map.pop(npu_id, None)


class InstancePackage:
    def __init__(self, instance, class_code, is_async, code_id) -> None:
        """
        package instance
        """
        self.__instance = instance
        self.__class_code = class_code
        self.__is_async = is_async
        self.__code_id = code_id

    def get_class_code(self):
        """get class code"""
        return self.__class_code

    def get_instance(self):
        """get class code"""
        return self.__instance

    def get_is_async(self):
        """get is_async"""
        return self.__is_async

    def get_code_id(self):
        """get code id"""
        return self.__code_id