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

import {IAtomicQuoteEngine} from "./interfaces/IAtomicQuoteEngine.sol";
import {IAtomicBridgeCoordinator} from "./interfaces/IAtomicBridgeCoordinator.sol";
import {IAtomicLiquidityVault} from "./interfaces/IAtomicLiquidityVault.sol";
import {IAtomicFulfillerRegistry} from "./interfaces/IAtomicFulfillerRegistry.sol";
import {AtomicFeePolicy} from "./AtomicFeePolicy.sol";
import {AtomicTypes} from "./AtomicTypes.sol";

contract AtomicQuoteEngine is IAtomicQuoteEngine {
    IAtomicBridgeCoordinator public immutable coordinator;
    IAtomicLiquidityVault public immutable vault;
    IAtomicFulfillerRegistry public immutable fulfillerRegistry;
    AtomicFeePolicy public immutable feePolicy;

    constructor(
        address coordinator_,
        address vault_,
        address fulfillerRegistry_,
        address feePolicy_
    ) {
        coordinator = IAtomicBridgeCoordinator(coordinator_);
        vault = IAtomicLiquidityVault(vault_);
        fulfillerRegistry = IAtomicFulfillerRegistry(fulfillerRegistry_);
        feePolicy = AtomicFeePolicy(feePolicy_);
    }

    function quote(
        bytes32 corridorId,
        uint256 amountIn,
        uint256 minAmountOut,
        address fulfiller
    ) external view returns (AtomicTypes.AtomicQuote memory q) {
        AtomicTypes.CorridorConfig memory cfg = coordinator.getCorridorConfig(corridorId);
        AtomicTypes.CorridorLiquidityState memory state = vault.getCorridorLiquidityState(corridorId, cfg.assetOut);
        (uint256 fulfillerFee, uint256 protocolFee) = feePolicy.quoteFees(corridorId, amountIn);
        uint256 requiredBond = feePolicy.requiredBond(corridorId, minAmountOut);
        bool authorized = fulfillerRegistry.isFulfillerAuthorized(fulfiller, corridorId);
        bool bondSufficient = fulfillerRegistry.canCover(fulfiller, requiredBond);

        q = AtomicTypes.AtomicQuote({
            routeClass: _routeClass(cfg, state, amountIn, minAmountOut, authorized, bondSufficient),
            availableLiquidity: state.freeLiquidity > state.targetBuffer ? state.freeLiquidity - state.targetBuffer : 0,
            freeLiquidity: state.freeLiquidity,
            fulfillerFee: fulfillerFee,
            protocolFee: protocolFee,
            requiredBond: requiredBond,
            settlementBacklog: state.settlementBacklog,
            deadlineWindow: cfg.fulfilmentTimeout,
            corridorEnabled: cfg.enabled,
            corridorDegraded: cfg.degraded,
            fulfillerAuthorized: authorized,
            fulfillerBondSufficient: bondSufficient
        });
    }

    function _routeClass(
        AtomicTypes.CorridorConfig memory cfg,
        AtomicTypes.CorridorLiquidityState memory state,
        uint256 amountIn,
        uint256 minAmountOut,
        bool authorized,
        bool bondSufficient
    ) internal pure returns (AtomicTypes.RouteClass) {
        if (!cfg.enabled || cfg.degraded) {
            return AtomicTypes.RouteClass.Blocked;
        }
        if (
            amountIn > cfg.maxNotional ||
            minAmountOut > state.freeLiquidity ||
            state.settlementBacklog > cfg.maxSettlementBacklog
        ) {
            return AtomicTypes.RouteClass.Blocked;
        }
        if (!authorized || !bondSufficient) {
            return AtomicTypes.RouteClass.Planning;
        }
        return AtomicTypes.RouteClass.ExecutionReady;
    }
}
