//
// Copyright (C) 2022-2026 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

// Compiler Interface

#pragma once

#include "intel_npu/config/config.hpp"
#include "openvino/runtime/profiling_info.hpp"
#include "vpux/compiler/network_metadata.hpp"

namespace vpux {

#ifndef ICOMPILER_MAKE_VERSION
/// @brief Generates npu compiler (generic 'oneAPI') API version number
#define ICOMPILER_MAKE_VERSION(_major, _minor) ((_major << 16) | (_minor & 0x0000ffff))
#endif  // ICOMPILER_MAKE_VERSION

/**
 * @interface ICompiler
 * @brief An interface to be implemented by a concrete compiler to provide
 * methods for preparing a network for execution on a NPU device
 */
class ICompiler : public std::enable_shared_from_this<ICompiler> {
public:
    /**
     * @brief Transforms a network from the OpenVINO model representation to a format executable
     * by a NPU device
     * @param model a shared pointer to the OpenVINO model to be compiled
     * @param config a reference to NPUConfig containing plugin config options
     *        including config options related to compilation
     * @return a shared pointer on an object implementing NetworkDescription interface
     */
    virtual NetworkDescription compile(const std::shared_ptr<const ov::Model>& model,
                                       const intel_npu::Config& config) const = 0;

    /**
     * @brief Compiles the model, weights separation enabled. All init schedules along with the main one are compiled in
     * the same scope.
     * @return A "NetworkDescription" object for each init schedule, followed by another one corresponding to the main
     * part.
     */
    virtual std::vector<std::shared_ptr<NetworkDescription>> compileWsOneShot(
            const std::shared_ptr<ov::Model>& /*model*/, const intel_npu::Config& /*config*/) const {
        OPENVINO_NOT_IMPLEMENTED;
    }

    /**
     * @brief Sequential compilation of Init(s) and Main
     *
     * "Stateless compiler" approach
     * We want to get multiple Inits in the case of a large number of weights.
     * This allows us to build pipeline:
     * Allocate W1 -> Init1
     *             Allocate W2 -> Init2
     *                          Allocate W3 -> Init2
     *
     * This is why there is an additional parameter callNumber:
     * Compiler should somehow understand which Init(or Main) to return
     * Plugin does not know total numbers of Init schedules
     */
    virtual NetworkDescription compileWsIterative(const std::shared_ptr<ov::Model>& /*model*/,
                                                  const intel_npu::Config& /*config*/, size_t /*callNumber*/) const {
        OPENVINO_NOT_IMPLEMENTED;
    }

    /**
     * @brief Returns information about supported layers of the network passed
     * @param model The model to be queried
     * @param config A reference to NPUConfig containing plugin config options
     *        including config options related to compilation
     * @returns SupportedOpsMap structure with information about supported layers
     */
    virtual ov::SupportedOpsMap query(const std::shared_ptr<const ov::Model>& model,
                                      const intel_npu::Config& config) const = 0;

    /**
     * @brief Parses already compiled network to extract meta information:
     *        inputs and outputs descriptions
     * @param network compiled network represented as a vector of char
     * @param config a reference to NPUConfig containing plugin config options
     *        Note: compilation options will be ignored,
     *        since the network is already compiled
     * @return a shared pointer on an object implementing NetworkDescription interface
     */
    virtual NetworkMetadata parse(const std::vector<uint8_t>& network, const intel_npu::Config& config) const = 0;

    /**
     * @brief Returns the compiler version
     * @return composite uint32_t value of compiler version.
     *         MSB 16 bits = Major version
     *         LSB 16bits = Minor version
     */
    virtual uint32_t get_version() const = 0;

    virtual std::vector<ov::ProfilingInfo> process_profiling_output(const std::vector<uint8_t>& profData,
                                                                    const std::vector<uint8_t>& network,
                                                                    const intel_npu::Config& config) const = 0;

protected:
    virtual ~ICompiler() = default;
};

}  // namespace vpux
