// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.19;

import { LiquidityManager } from "../../src/LiquidityManager.sol";
import { OptimizerV3Push3 } from "../../src/OptimizerV3Push3.sol";
import { BacktestKraiken } from "./BacktestKraiken.sol";
import { MockToken } from "./MockToken.sol";

/**
 * @notice Deployment result for the KrAIken system on the shadow pool.
 */
struct KrAIkenSystem {
    BacktestKraiken kraiken;
    /// @dev OptimizerV3Push3 is used as the optimizer address. Its getLiquidityParams()
    ///      always reverts; LM's try/catch then falls back to bear-mode defaults on every
    ///      recenter. This is intentional for backtesting.
    OptimizerV3Push3 optimizer;
    LiquidityManager lm;
}

/**
 * @title KrAIkenDeployer
 * @notice Library that deploys the KrAIken protocol contracts on top of a shadow pool
 *         for backtesting purposes.
 *
 * Deployment order follows DeployLocal.sol:
 *   1. Deploy OptimizerV3Push3 (no proxy — it only exposes isBullMarket(), so LM falls
 *      back to bear-mode defaults via try/catch on every recenter call).
 *   2. Deploy LiquidityManager pointing at the shadow factory + mock WETH + BacktestKraiken.
 *   3. Wire BacktestKraiken → LM (setLiquidityManager).
 *   4. Set fee destination on LM.
 *   5. Fund LM with mock WETH (initial capital).
 *
 * @dev All functions are `internal` so they are inlined into BacktestRunner.s.sol,
 *      keeping msg.sender consistent with the broadcaster throughout deployment.
 */
library KrAIkenDeployer {
    uint256 internal constant DEFAULT_INITIAL_CAPITAL = 10 ether;

    /**
     * @notice Deploy the KrAIken system with default initial capital (10 ETH equivalent).
     */
    function deploy(address shadowFactory, address mockWeth, address krkToken, address feeDestination) internal returns (KrAIkenSystem memory sys) {
        return deploy(shadowFactory, mockWeth, krkToken, feeDestination, DEFAULT_INITIAL_CAPITAL);
    }

    /**
     * @notice Deploy the KrAIken system with configurable initial capital.
     *
     * @param shadowFactory   Factory that created the shadow pool.
     * @param mockWeth        Mock WETH token address (18-decimal ERC-20, freely mintable).
     * @param krkToken        BacktestKraiken token address (setLiquidityManager not yet called).
     * @param feeDestination  Address that will receive LP fees; also used as the caller
     *                        for subsequent setRecenterAccess() calls.
     * @param initialCapital  Mock WETH minted to LM so recenter() has capital to deploy.
     */
    function deploy(
        address shadowFactory,
        address mockWeth,
        address krkToken,
        address feeDestination,
        uint256 initialCapital
    )
        internal
        returns (KrAIkenSystem memory sys)
    {
        // 1. Deploy OptimizerV3Push3.
        //    OptimizerV3Push3.getLiquidityParams() always reverts; LM's try/catch falls
        //    back to bear defaults on every recenter — conservative and correct for a
        //    baseline backtest.
        OptimizerV3Push3 optimizer = new OptimizerV3Push3();

        // 2. Deploy LiquidityManager. It computes the pool address from factory + WETH +
        //    KRK + FEE (10 000). The shadow pool must have been created with the same
        //    factory and the same fee tier (ShadowPoolDeployer.SHADOW_FEE == 10 000).
        LiquidityManager lm = new LiquidityManager(shadowFactory, mockWeth, krkToken, address(optimizer));

        // 3. Wire BacktestKraiken → LM so the restricted mint/burn functions work.
        BacktestKraiken(krkToken).setLiquidityManager(address(lm));

        // 4. Set fee destination (required before setRecenterAccess can be called).
        lm.setFeeDestination(feeDestination);

        // 5. Fund LM with mock WETH. recenter() uses _getEthBalance() which reads
        //    weth.balanceOf(address(this)). Pre-funding avoids calling weth.deposit()
        //    (which MockToken does not implement).
        MockToken(mockWeth).mint(address(lm), initialCapital);

        sys = KrAIkenSystem({ kraiken: BacktestKraiken(krkToken), optimizer: optimizer, lm: lm });
    }
}
