// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

import {IPool} from '../../interfaces/IPool.sol';
import {IPoolConfigurator} from '../../interfaces/IPoolConfigurator.sol';
import {IAaveOracle} from '../../interfaces/IAaveOracle.sol';
import {IDefaultInterestRateStrategyV2} from '../../interfaces/IDefaultInterestRateStrategyV2.sol';

/// @dev Examples here assume the usage of the `AaveV3Payload` base contracts
/// contained in this same repository
interface IAaveV3ConfigEngine {
  struct Basic {
    string assetSymbol;
    TokenImplementations implementations;
  }

  struct EngineLibraries {
    address listingEngine;
    address eModeEngine;
    address borrowEngine;
    address collateralEngine;
    address priceFeedEngine;
    address rateEngine;
    address capsEngine;
  }

  struct EngineConstants {
    IPool pool;
    IPoolConfigurator poolConfigurator;
    IAaveOracle oracle;
    address rewardsController;
    address collector;
    address defaultInterestRateStrategy;
  }

  struct InterestRateInputData {
    uint256 optimalUsageRatio;
    uint256 baseVariableBorrowRate;
    uint256 variableRateSlope1;
    uint256 variableRateSlope2;
  }

  /**
   * @dev Required for naming of a/v/s tokens
   * Example (mock):
   * PoolContext({
   *   networkName: 'Polygon',
   *   networkAbbreviation: 'Pol'
   * })
   */
  struct PoolContext {
    string networkName;
    string networkAbbreviation;
  }

  /**
   * @dev Example (mock):
   * Listing({
   *   asset: 0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9,
   *   assetSymbol: 'AAVE',
   *   priceFeed: 0x547a514d5e3769680Ce22B2361c10Ea13619e8a9,
   *   rateStrategyParams: InterestRateInputData({
   *     optimalUsageRatio: 80_00,
   *     baseVariableBorrowRate: 25, // 0.25%
   *     variableRateSlope1: 3_00,
   *     variableRateSlope2: 75_00
   *   }),
   *   enabledToBorrow: EngineFlags.ENABLED,
   *   flashloanable: EngineFlags.ENABLED,
   *   borrowableInIsolation: EngineFlags.ENABLED,
   *   withSiloedBorrowing:, EngineFlags.DISABLED,
   *   ltv: 70_50, // 70.5%
   *   liqThreshold: 76_00, // 76%
   *   liqBonus: 5_00, // 5%
   *   reserveFactor: 10_00, // 10%
   *   supplyCap: 100_000, // 100k AAVE
   *   borrowCap: 60_000, // 60k AAVE
   *   debtCeiling: 100_000, // 100k USD
   *   liqProtocolFee: 10_00, // 10%
   *   eModeCategory: 0, // No category
   * }
   */
  struct Listing {
    address asset;
    string assetSymbol;
    address priceFeed;
    InterestRateInputData rateStrategyParams; // Mandatory, no matter if enabled for borrowing or not
    uint256 enabledToBorrow;
    uint256 borrowableInIsolation; // Only considered is enabledToBorrow == EngineFlags.ENABLED (true)
    uint256 withSiloedBorrowing; // Only considered if enabledToBorrow == EngineFlags.ENABLED (true)
    uint256 flashloanable; // Independent from enabled to borrow: an asset can be flashloanble and not enabled to borrow
    uint256 ltv; // Only considered if liqThreshold > 0
    uint256 liqThreshold; // If `0`, the asset will not be enabled as collateral
    uint256 liqBonus; // Only considered if liqThreshold > 0
    uint256 reserveFactor; // Only considered if enabledToBorrow == EngineFlags.ENABLED (true)
    uint256 supplyCap; // If passing any value distinct to EngineFlags.KEEP_CURRENT, always configured
    uint256 borrowCap; // If passing any value distinct to EngineFlags.KEEP_CURRENT, always configured
    uint256 debtCeiling; // Only considered if liqThreshold > 0
    uint256 liqProtocolFee; // Only considered if liqThreshold > 0
  }

  struct RepackedListings {
    address[] ids;
    Basic[] basics;
    BorrowUpdate[] borrowsUpdates;
    CollateralUpdate[] collateralsUpdates;
    PriceFeedUpdate[] priceFeedsUpdates;
    CapsUpdate[] capsUpdates;
    IDefaultInterestRateStrategyV2.InterestRateData[] rates;
  }

  struct TokenImplementations {
    address aToken;
    address vToken;
  }

  struct ListingWithCustomImpl {
    Listing base;
    TokenImplementations implementations;
  }

  /**
   * @dev Example (mock):
   * CapsUpdate({
   *   asset: AaveV3EthereumAssets.AAVE_UNDERLYING,
   *   supplyCap: 1_000_000,
   *   borrowCap: EngineFlags.KEEP_CURRENT
   * }
   */
  struct CapsUpdate {
    address asset;
    uint256 supplyCap; // Pass any value, of EngineFlags.KEEP_CURRENT to keep it as it is
    uint256 borrowCap; // Pass any value, of EngineFlags.KEEP_CURRENT to keep it as it is
  }

  /**
   * @dev Example (mock):
   * PriceFeedUpdate({
   *   asset: AaveV3EthereumAssets.AAVE_UNDERLYING,
   *   priceFeed: 0x547a514d5e3769680Ce22B2361c10Ea13619e8a9
   * })
   */
  struct PriceFeedUpdate {
    address asset;
    address priceFeed;
  }

  /**
   * @dev Example (mock):
   * CollateralUpdate({
   *   asset: AaveV3EthereumAssets.AAVE_UNDERLYING,
   *   ltv: 60_00,
   *   liqThreshold: 70_00,
   *   liqBonus: EngineFlags.KEEP_CURRENT,
   *   debtCeiling: EngineFlags.KEEP_CURRENT,
   *   liqProtocolFee: 7_00
   * })
   */
  struct CollateralUpdate {
    address asset;
    uint256 ltv;
    uint256 liqThreshold;
    uint256 liqBonus;
    uint256 debtCeiling;
    uint256 liqProtocolFee;
  }

  /**
   * @dev Example (mock):
   * BorrowUpdate({
   *   asset: AaveV3EthereumAssets.AAVE_UNDERLYING,
   *   enabledToBorrow: EngineFlags.ENABLED,
   *   flashloanable: EngineFlags.KEEP_CURRENT,
   *   borrowableInIsolation: EngineFlags.KEEP_CURRENT,
   *   withSiloedBorrowing: EngineFlags.KEEP_CURRENT,
   *   reserveFactor: 15_00, // 15%
   * })
   */
  struct BorrowUpdate {
    address asset;
    uint256 enabledToBorrow;
    uint256 flashloanable;
    uint256 borrowableInIsolation;
    uint256 withSiloedBorrowing;
    uint256 reserveFactor;
  }

  /**
   * @dev Example (mock):
   * AssetEModeUpdate({
   *   asset: AaveV3EthereumAssets.rETH_UNDERLYING,
   *   eModeCategory: 1, // ETH correlated
   *   borrowable: EngineFlags.ENABLED,
   *   collateral: EngineFlags.KEEP_CURRENT,
   * })
   */
  struct AssetEModeUpdate {
    address asset;
    uint8 eModeCategory;
    uint256 borrowable;
    uint256 collateral;
  }

  /**
   * @dev Example (mock):
   * EModeCategoryUpdate({
   *   eModeCategory: 1, // ETH correlated
   *   ltv: 60_00,
   *   liqThreshold: 70_00,
   *   liqBonus: EngineFlags.KEEP_CURRENT,
   *   label: EngineFlags.KEEP_CURRENT_STRING
   * })
   */
  struct EModeCategoryUpdate {
    uint8 eModeCategory;
    uint256 ltv;
    uint256 liqThreshold;
    uint256 liqBonus;
    string label;
  }

  /**
   * @dev Example (mock):
   * RateStrategyUpdate({
   *   asset: AaveV3OptimismAssets.USDT_UNDERLYING,
   *   params: InterestRateInputData({
   *     optimalUsageRatio: _bpsToRay(80_00),
   *     baseVariableBorrowRate: EngineFlags.KEEP_CURRENT,
   *     variableRateSlope1: EngineFlags.KEEP_CURRENT,
   *     variableRateSlope2: _bpsToRay(75_00)
   *   })
   * })
   */
  struct RateStrategyUpdate {
    address asset;
    InterestRateInputData params;
  }

  /**
   * @notice Performs full listing of the assets, in the Aave pool configured in this engine instance
   * @param context `PoolContext` struct, effectively meta-data for naming of a/v/s tokens.
   *   More information on the documentation of the struct.
   * @param listings `Listing[]` list of declarative configs for every aspect of the asset listings.
   *   More information on the documentation of the struct.
   */
  function listAssets(PoolContext memory context, Listing[] memory listings) external;

  /**
   * @notice Performs full listings of assets, in the Aave pool configured in this engine instance
   * @dev This function allows more customization, especifically enables to set custom implementations
   *   for a/v/s tokens.
   *   IMPORTANT. Use it only if understanding the internals of the Aave v3 protocol
   * @param context `PoolContext` struct, effectively meta-data for naming of a/v/s tokens.
   *   More information on the documentation of the struct.
   * @param listings `ListingWithCustomImpl[]` list of declarative configs for every aspect of the asset listings.
   */
  function listAssetsCustom(
    PoolContext memory context,
    ListingWithCustomImpl[] memory listings
  ) external;

  /**
   * @notice Performs an update of the caps (supply, borrow) of the assets, in the Aave pool configured in this engine instance
   * @param updates `CapsUpdate[]` list of declarative updates containing the new caps
   *   More information on the documentation of the struct.
   */
  function updateCaps(CapsUpdate[] memory updates) external;

  /**
   * @notice Performs an update on the rate strategy params of the assets, in the Aave pool configured in this engine instance
   * @dev The engine itself manages if a new rate strategy needs to be deployed or if an existing one can be re-used
   * @param updates `RateStrategyUpdate[]` list of declarative updates containing the new rate strategy params
   *   More information on the documentation of the struct.
   */
  function updateRateStrategies(RateStrategyUpdate[] memory updates) external;

  /**
   * @notice Performs an update of the collateral-related params of the assets, in the Aave pool configured in this engine instance
   * @param updates `CollateralUpdate[]` list of declarative updates containing the new parameters
   *   More information on the documentation of the struct.
   */
  function updateCollateralSide(CollateralUpdate[] memory updates) external;

  /**
   * @notice Performs an update of the price feed of the assets, in the Aave pool configured in this engine instance
   * @param updates `PriceFeedUpdate[]` list of declarative updates containing the new parameters
   *   More information on the documentation of the struct.
   */
  function updatePriceFeeds(PriceFeedUpdate[] memory updates) external;

  /**
   * @notice Performs an update of the borrow-related params of the assets, in the Aave pool configured in this engine instance
   * @param updates `BorrowUpdate[]` list of declarative updates containing the new parameters
   *   More information on the documentation of the struct.
   */
  function updateBorrowSide(BorrowUpdate[] memory updates) external;

  /**
   * @notice Performs an update of the e-mode categories, in the Aave pool configured in this engine instance
   * @param updates `EModeCategoryUpdate[]` list of declarative updates containing the new parameters
   *   More information on the documentation of the struct.
   */
  function updateEModeCategories(EModeCategoryUpdate[] memory updates) external;

  /**
   * @notice Performs an update of the e-mode category.
   * Sets a specified asset collateral and/or borrowable, in the Aave pool configured in this engine instance
   * @param updates `EModeCollateralUpdate[]` list of declarative updates containing the new parameters
   *   More information on the documentation of the struct.
   */
  function updateAssetsEMode(AssetEModeUpdate[] calldata updates) external;

  function DEFAULT_INTEREST_RATE_STRATEGY() external view returns (address);

  function POOL() external view returns (IPool);

  function POOL_CONFIGURATOR() external view returns (IPoolConfigurator);

  function ORACLE() external view returns (IAaveOracle);

  function ATOKEN_IMPL() external view returns (address);

  function VTOKEN_IMPL() external view returns (address);

  function REWARDS_CONTROLLER() external view returns (address);

  function COLLECTOR() external view returns (address);

  function BORROW_ENGINE() external view returns (address);

  function CAPS_ENGINE() external view returns (address);

  function COLLATERAL_ENGINE() external view returns (address);

  function EMODE_ENGINE() external view returns (address);

  function LISTING_ENGINE() external view returns (address);

  function PRICE_FEED_ENGINE() external view returns (address);

  function RATE_ENGINE() external view returns (address);
}
