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

import "./Aggregator.sol";
import "../ccip/CCIPSender.sol";

/**
 * @title Oracle Aggregator with CCIP Integration
 * @notice Extends Aggregator with CCIP cross-chain messaging capabilities
 * @dev Automatically sends oracle updates to other chains via CCIP when updates occur
 */
contract OracleWithCCIP is Aggregator {
    CCIPSender public ccipSender;
    bool public ccipEnabled;
    
    // Destination chain configurations (using CCIPSender's destinations)
    uint64[] public ccipDestinationChains;
    
    event CCIPUpdateSent(
        bytes32 indexed messageId,
        uint64 indexed destinationChainSelector,
        uint256 answer,
        uint256 roundId
    );
    event CCIPEnabled(bool enabled);
    event CCIPSenderUpdated(address oldSender, address newSender);
    
    constructor(
        string memory _description,
        address _admin,
        uint256 _heartbeat,
        uint256 _deviationThreshold,
        address _ccipSender
    ) Aggregator(_description, _admin, _heartbeat, _deviationThreshold) {
        require(_ccipSender != address(0), "OracleWithCCIP: zero sender address");
        ccipSender = CCIPSender(_ccipSender);
        ccipEnabled = true;
    }
    
    /**
     * @notice Update the answer and send to CCIP destinations
     * @param answer New answer value
     */
    function updateAnswer(uint256 answer) external override onlyTransmitter whenNotPaused {
        uint256 currentRound = latestRound;
        Round storage round = rounds[currentRound];
        
        // Check if we need to start a new round
        if (round.updatedAt == 0 || 
            block.timestamp >= round.startedAt + heartbeat ||
            shouldUpdate(answer, round.answer)) {
            currentRound = latestRound + 1;
            latestRound = currentRound;
            
            rounds[currentRound] = Round({
                answer: answer,
                startedAt: block.timestamp,
                updatedAt: block.timestamp,
                answeredInRound: currentRound,
                transmitter: msg.sender
            });
            
            emit NewRound(currentRound, msg.sender, block.timestamp);
            
            // Send to CCIP destinations if enabled
            if (ccipEnabled) {
                _sendToCCIP(currentRound, answer);
            }
        } else {
            // Update existing round
            round.updatedAt = block.timestamp;
            round.transmitter = msg.sender;
        }
        
        emit AnswerUpdated(int256(answer), currentRound, block.timestamp);
    }
    
    /**
     * @notice Send oracle update to all CCIP destinations
     */
    function _sendToCCIP(uint256 roundId, uint256 answer) internal {
        uint64[] memory destinations = ccipSender.getDestinationChains();
        
        for (uint256 i = 0; i < destinations.length; i++) {
            uint64 chainSelector = destinations[i];
            
            try ccipSender.sendOracleUpdate(
                chainSelector,
                answer,
                roundId,
                block.timestamp
            ) returns (bytes32 messageId) {
                emit CCIPUpdateSent(messageId, chainSelector, answer, roundId);
            } catch {
                // Log error but don't revert
                // In production, consider adding error tracking
            }
        }
    }
    
    /**
     * @notice Enable/disable CCIP
     */
    function setCCIPEnabled(bool enabled) external {
        require(msg.sender == admin, "OracleWithCCIP: only admin");
        ccipEnabled = enabled;
        emit CCIPEnabled(enabled);
    }
    
    /**
     * @notice Update CCIP sender
     */
    function updateCCIPSender(address newSender) external {
        require(msg.sender == admin, "OracleWithCCIP: only admin");
        require(newSender != address(0), "OracleWithCCIP: zero address");
        
        address oldSender = address(ccipSender);
        ccipSender = CCIPSender(newSender);
        
        emit CCIPSenderUpdated(oldSender, newSender);
    }
    
    /**
     * @notice Get CCIP destinations
     */
    function getCCIPDestinations() external view returns (uint64[] memory) {
        return ccipSender.getDestinationChains();
    }
    
    /**
     * @notice Get fee for sending to CCIP destination
     */
    function getCCIPFee(uint64 chainSelector) external view returns (uint256) {
        bytes memory data = abi.encode(uint256(0), uint256(0), uint256(0));
        return ccipSender.calculateFee(chainSelector, data);
    }
}

