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

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

/**
 * @title YTToken
 * @notice YT代币示例实现（Yield Token）
 * @dev 展示如何实现价格接口供YTPriceFeed读取
 */
contract YTToken is ERC20, Ownable {

    error NotUpdater();
    error InvalidUpdater();
    error IntervalTooLong();
    error UpdateTooFrequent();
    error InvalidYield();
    error InvalidAmount();
    error InsufficientAssets();
    
    uint256 public constant PRICE_PRECISION = 10 ** 30;
    
    uint256 public totalAssets;
    uint256 public accumulatedYield;
    
    // 价格变量
    uint256 public assetPrice;
    uint256 public lastPriceUpdate;
    
    // 价格更新控制
    address public priceUpdater;
    uint256 public minUpdateInterval = 5 minutes; // 最小更新间隔
    
    event PriceUpdated(uint256 oldPrice, uint256 newPrice, uint256 timestamp);
    event YieldAccumulated(uint256 amount, uint256 timestamp);
    event PriceUpdaterSet(address indexed updater);
    event MinUpdateIntervalSet(uint256 interval);
    
    modifier onlyPriceUpdater() {
        if (msg.sender != priceUpdater && msg.sender != owner()) revert NotUpdater();
        _;
    }
    
    constructor(
        string memory name,
        string memory symbol,
        address _priceUpdater
    ) ERC20(name, symbol) Ownable(msg.sender) {
        assetPrice = PRICE_PRECISION; // 初始价格为1
        lastPriceUpdate = block.timestamp;
        priceUpdater = _priceUpdater;
    }
    
    /**
     * @notice 设置价格更新者
     */
    function setPriceUpdater(address _updater) external onlyOwner {
        if (_updater == address(0)) revert InvalidUpdater();
        priceUpdater = _updater;
        emit PriceUpdaterSet(_updater);
    }
    
    /**
     * @notice 设置最小更新间隔
     */
    function setMinUpdateInterval(uint256 _interval) external onlyOwner {
        if (_interval > 1 hours) revert IntervalTooLong();
        minUpdateInterval = _interval;
        emit MinUpdateIntervalSet(_interval);
    }
    
    /**
     * @notice 更新代币价格
     * @dev 只能由授权的updater调用，有最小时间间隔限制
     */
    function updatePrice() public onlyPriceUpdater {
        if (block.timestamp < lastPriceUpdate + minUpdateInterval) revert UpdateTooFrequent();
        
        uint256 oldPrice = assetPrice;
        uint256 supply = totalSupply();
        
        if (supply == 0) {
            assetPrice = PRICE_PRECISION;
        } else {
            uint256 totalValue = totalAssets + accumulatedYield;
            // 计算每个token对应的USDC价值（18位精度）
            uint256 usdcPerToken = totalValue * 1e18 / supply;
            // 转换为30位精度的价格
            assetPrice = usdcPerToken * PRICE_PRECISION / 1e18;
        }
        
        lastPriceUpdate = block.timestamp;
        
        emit PriceUpdated(oldPrice, assetPrice, block.timestamp);
    }
    
    /**
     * @notice 累积收益并更新价格
     * @dev 当从收益策略中收到新收益时调用
     */
    function updateYield(uint256 _newYield) external onlyPriceUpdater {
        if (_newYield == 0) revert InvalidYield();
        
        accumulatedYield += _newYield;
        
        emit YieldAccumulated(_newYield, block.timestamp);
        
        // 收益更新后立即更新价格
        if (block.timestamp >= lastPriceUpdate + minUpdateInterval) {
            uint256 oldPrice = assetPrice;
            uint256 supply = totalSupply();
            
            if (supply > 0) {
                uint256 totalValue = totalAssets + accumulatedYield;
                uint256 usdcPerToken = totalValue * 1e18 / supply;
                assetPrice = usdcPerToken * PRICE_PRECISION / 1e18;
            }
            
            lastPriceUpdate = block.timestamp;
            emit PriceUpdated(oldPrice, assetPrice, block.timestamp);
        }
    }
    
    /**
     * @notice 存入资产（模拟）
     * @dev 实际实现中应该处理真实的USDC存款
     */
    function deposit(uint256 _amount) external onlyOwner {
        if (_amount == 0) revert InvalidAmount();
        totalAssets += _amount;
        _mint(msg.sender, _amount);
    }
    
    /**
     * @notice 提取资产（模拟）
     * @dev 实际实现中应该处理真实的USDC提款
     */
    function withdraw(uint256 _amount) external onlyOwner {
        if (_amount == 0) revert InvalidAmount();
        if (totalAssets < _amount) revert InsufficientAssets();
        totalAssets -= _amount;
        _burn(msg.sender, _amount);
    }
    
    /**
     * @notice 获取当前价格信息
     */
    function getPriceInfo() external view returns (
        uint256 price,
        uint256 lastUpdate,
        uint256 timeSinceUpdate,
        uint256 totalVal
    ) {
        price = assetPrice;
        lastUpdate = lastPriceUpdate;
        timeSinceUpdate = block.timestamp - lastPriceUpdate;
        totalVal = totalAssets + accumulatedYield;
    }
}

