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

import "@openzeppelin/contracts/access/AccessControl.sol";
import "../oracle/IAggregator.sol";
import "./IReserveSystem.sol";

/**
 * @title OraclePriceFeed
 * @notice Integrates Reserve System with Chainlink-compatible oracle aggregators
 * @dev Provides price feeds from multiple sources with aggregation and validation
 */
contract OraclePriceFeed is AccessControl {
    bytes32 public constant PRICE_FEED_UPDATER_ROLE = keccak256("PRICE_FEED_UPDATER_ROLE");

    IReserveSystem public reserveSystem;

    // Asset to aggregator mapping
    mapping(address => address) public aggregators;
    // Asset to price multiplier (for decimals conversion)
    mapping(address => uint256) public priceMultipliers;

    // Price feed update interval (seconds)
    uint256 public updateInterval = 30;

    // Last update timestamp per asset
    mapping(address => uint256) public lastUpdateTime;

    event AggregatorSet(address indexed asset, address indexed aggregator, uint256 multiplier);
    event PriceFeedUpdated(address indexed asset, uint256 price, uint256 timestamp);

    constructor(address admin, address reserveSystem_) {
        _grantRole(DEFAULT_ADMIN_ROLE, admin);
        _grantRole(PRICE_FEED_UPDATER_ROLE, admin);

        reserveSystem = IReserveSystem(reserveSystem_);
    }

    /**
     * @notice Set aggregator for an asset
     * @param asset Address of the asset
     * @param aggregator Address of the Chainlink aggregator
     * @param multiplier Price multiplier for decimals conversion (e.g., 1e10 for 8-decimal aggregator to 18 decimals)
     */
    function setAggregator(
        address asset,
        address aggregator,
        uint256 multiplier
    ) external onlyRole(DEFAULT_ADMIN_ROLE) {
        require(asset != address(0), "OraclePriceFeed: zero asset");
        require(aggregator != address(0), "OraclePriceFeed: zero aggregator");
        require(multiplier > 0, "OraclePriceFeed: zero multiplier");

        aggregators[asset] = aggregator;
        priceMultipliers[asset] = multiplier;

        emit AggregatorSet(asset, aggregator, multiplier);
    }

    /**
     * @notice Update price feed from aggregator
     * @param asset Address of the asset
     */
    function updatePriceFeed(address asset) public onlyRole(PRICE_FEED_UPDATER_ROLE) {
        address aggregator = aggregators[asset];
        require(aggregator != address(0), "OraclePriceFeed: aggregator not set");

        IAggregator agg = IAggregator(aggregator);
        (, int256 answer, , uint256 updatedAt, ) = agg.latestRoundData();

        require(answer > 0, "OraclePriceFeed: invalid price");
        require(updatedAt > 0, "OraclePriceFeed: invalid timestamp");
        require(block.timestamp - updatedAt <= updateInterval * 2, "OraclePriceFeed: stale price");

        uint256 price = uint256(answer) * priceMultipliers[asset];

        reserveSystem.updatePriceFeed(asset, price, updatedAt);

        lastUpdateTime[asset] = block.timestamp;

        emit PriceFeedUpdated(asset, price, updatedAt);
    }

    /**
     * @notice Update multiple price feeds
     * @param assets Array of asset addresses
     */
    function updateMultiplePriceFeeds(address[] calldata assets) external onlyRole(PRICE_FEED_UPDATER_ROLE) {
        for (uint256 i = 0; i < assets.length; i++) {
            updatePriceFeed(assets[i]);
        }
    }

    /**
     * @notice Get current price from aggregator and update reserve system
     * @param asset Address of the asset
     * @return price Current price
     * @return timestamp Price timestamp
     */
    function getAndUpdatePrice(address asset) external returns (uint256 price, uint256 timestamp) {
        updatePriceFeed(asset);
        return reserveSystem.getPrice(asset);
    }

    /**
     * @notice Set update interval
     * @param interval New update interval in seconds
     */
    function setUpdateInterval(uint256 interval) external onlyRole(DEFAULT_ADMIN_ROLE) {
        require(interval > 0, "OraclePriceFeed: zero interval");
        updateInterval = interval;
    }

    /**
     * @notice Check if price feed needs update
     * @param asset Address of the asset
     * @return updateNeeded True if update is needed
     */
    function needsUpdate(address asset) external view returns (bool updateNeeded) {
        uint256 lastUpdate = lastUpdateTime[asset];
        if (lastUpdate == 0) {
            return true;
        }
        return block.timestamp - lastUpdate >= updateInterval;
    }
}

