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

import "@openzeppelin/contracts/access/AccessControl.sol";

/**
 * @title WLPNAVOracle
 * @notice Chainlink-style read interface for wLP / vault share price in USD (8 decimals) for lending adapters.
 * @dev Keeper updates `latestAnswer` + `updatedAt`. Consumers must check `isStale()` before liquidations.
 */
contract WLPNAVOracle is AccessControl {
    bytes32 public constant KEEPER_ROLE = keccak256("KEEPER_ROLE");

    /// @notice Price with 8 decimals (Chainlink USD convention).
    int256 public latestAnswer;
    uint256 public updatedAt;
    uint256 public heartbeat;
    bool public circuitBreaker;

    event AnswerUpdated(int256 indexed answer, uint256 updatedAt, address indexed keeper);
    event HeartbeatUpdated(uint256 heartbeat);
    event CircuitBreakerSet(bool tripped);

    constructor(address admin, uint256 heartbeat_) {
        require(admin != address(0), "NAV: zero admin");
        heartbeat = heartbeat_;
        _grantRole(DEFAULT_ADMIN_ROLE, admin);
    }

    function setHeartbeat(uint256 h) external onlyRole(DEFAULT_ADMIN_ROLE) {
        heartbeat = h;
        emit HeartbeatUpdated(h);
    }

    function setCircuitBreaker(bool on) external onlyRole(DEFAULT_ADMIN_ROLE) {
        circuitBreaker = on;
        emit CircuitBreakerSet(on);
    }

    function submitAnswer(int256 answer) external onlyRole(KEEPER_ROLE) {
        require(!circuitBreaker, "NAV: breaker");
        latestAnswer = answer;
        updatedAt = block.timestamp;
        emit AnswerUpdated(answer, updatedAt, msg.sender);
    }

    function isStale() external view returns (bool) {
        if (circuitBreaker) return true;
        if (heartbeat == 0) return false;
        return block.timestamp > updatedAt + heartbeat;
    }
}
