import ETFTOKEN from "../abis/CryptoETFToken.json";
import CETO from "../abis/CryptoETFOracle.json";
import ROUTER from "../abis/CryptoETFRouter.json";
import ETFFACTORY from "../abis/CryptoETFTokenFactory.json";
import { Contract, ethers } from "ethers";
import type { ETFCreateParams, ETFBurnParams, MintETFTokenParams, ETFCreateResult, MintETFResult } from '../types/params';

export class DexClientEVM {
    public readonly factory: Contract;
    public readonly router: Contract;
    public readonly oracle: Contract;
    public readonly signer: ethers.JsonRpcSigner;

    // 常量定义
    private readonly WETH: string;

    constructor(
        signer: ethers.JsonRpcSigner,
        addresses: {
            TWAP: string;
            CETO: string;
            ETFROUTER: string;
            ETFFACTORY: string;
            WETH: string;
        }
        // , network: "localhost" | "arbitrumSepolia" | "sepolia"
    ) {
        this.factory = new ethers.Contract(addresses.ETFFACTORY, ETFFACTORY.abi, signer);
        this.router = new ethers.Contract(addresses.ETFROUTER, ROUTER.abi, signer);
        this.oracle = new ethers.Contract(addresses.CETO, CETO.abi, signer);
        this.signer = signer;
        this.WETH = addresses.WETH;
    }

    public async createETF(params: ETFCreateParams): Promise<ETFCreateResult> {
        try {
            const { name, symbol, description: tokenUri, assets } = params;

            // 检查是否已存在
            const existingETF = await this.factory.etfListM(symbol);
            if (existingETF !== ethers.ZeroAddress) {
                return {
                    success: false,
                    error: 'ETF already exists',
                    data: {
                        etfAddress: existingETF,
                        symbol
                    }
                };
            }

            // 创建 ETF
            const tx = await this.factory.createETF(
                name,
                symbol,
                tokenUri,
                assets.map(asset => ({
                    tokenAddress: asset.token,
                    distribution: asset.weight // 5000
                }))
            );
            await tx.wait();

            // 获取创建的 ETF 地址
            const etfAddress = await this.factory.etfListM(symbol);
            console.log(`Created ETF at address: ${etfAddress}`);

            return {
                success: true,
                txid: tx.hash,
                data: {
                    etfAddress,
                    symbol,
                    name
                }
            };
        } catch (error) {
            console.error("Error in createETF:", error);
            return {
                success: false,
                txid: '',
                error: error instanceof Error ? error.message : 'Failed to create ETF'
            };
        }
    }

    public async purchaseETF(params: MintETFTokenParams): Promise<MintETFResult> {
        try {
            const { etfAddress, lamports } = params;
            // 检查用户余额
            const userAddress = await this.signer.getAddress();
            const balance = await this.signer.provider?.getBalance(userAddress);

            console.log(
                "USER ETH=>",
                ethers.formatEther(balance)
            );
            // 获取最新 NAV
            const nav = await this.oracle.nav(etfAddress, this.WETH, 10);
            console.log('Current ETF NAV:', ethers.formatEther(nav), 'ETH');

            // 设置截止时间
            const deadline = Math.round(Date.now() / 1000) + 100;

            // 购买 ETF
            const tx = await this.router.purchaseWithExactEth(
                etfAddress,
                this.signer.address,
                0,
                deadline,
                { value: ethers.parseUnits(lamports.toString()) }
            );
            const receipt = await tx.wait();

            // 获取 ETF 合约实例

            const etfBalance = await this.getETFBalance(etfAddress);

            return {
                success: true,
                txid: receipt.transactionHash,
                data: {
                    balance: etfBalance.toString(),
                    etfAddress
                }
            };
        } catch (error) {
            console.error("Error in purchaseETF:", error);
            return {
                success: false,
                txid: '',
                error: error instanceof Error ? error.message : 'Failed to purchase ETF'
            };
        }
    }

    public async burnETF(params: ETFBurnParams): Promise<MintETFResult> {
        try {
            const { etfAddress, lamports } = params;
            const deadline = Math.round(Date.now() / 1000) + 100;

            // 赎回 ETF
            const tx = await this.router.redeemWithExactEth(
                etfAddress,
                lamports,
                this.signer.address,
                0,
                deadline
            );
            const receipt = await tx.wait();

            const etfBalance = await this.getETFBalance(etfAddress);

            return {
                success: true,
                txid: receipt.transactionHash,
                data: {
                    balance: etfBalance.toString(),
                    etfAddress
                }
            };
        } catch (error) {
            console.error("Error in burnETF:", error);
            return {
                success: false,
                txid: '',
                error: error instanceof Error ? error.message : 'Failed to burn ETF'
            };
        }
    }

    // 查询方法
    public async getETFInfo(etfAddress: string) {
        const etfContract = new ethers.Contract(etfAddress, ETFTOKEN.abi, this.signer);
        const totalSupply = await etfContract.totalSupply();

        // 获取组成部分信息
        const constituentTokens = await etfContract.getConstituentTokens();
        const reserves = await Promise.all(
            constituentTokens.map(async (token: string) => ({
                token,
                reserve: await etfContract.constitunentsReserves(token)
            }))
        );

        return {
            totalSupply: totalSupply.toString(),
            reserves
        };
    }

    public async getETFBalance(etfAddress: string) {
        const etfContract = new ethers.Contract(etfAddress, ETFTOKEN.abi, this.signer);
        return await etfContract.balanceOf(this.signer.address);
    }

    public async getNav(etfAddress: string) {
        return await this.oracle.nav(etfAddress, this.WETH, 10);
    }

    // async function checkResult(etf, ceto) {
    //     console.log("======BEGIN TO CHECK STATE=====");
    //     const [signer1] = await ethers.getSigners();
    //     const etfC = await ethers.getContractAt(ETFTOKENABI, etf);
    //     console.log("MINT TOTAL  ETF=>", await etfC.totalSupply());
    //     //检查etf reverse
    //     for (const _consti of constitunents) {
    //       let _token = await ethers.getContractAt(ERC20ABI, _consti.tokenAddress);
    //       console.log(
    //         "RESERVE %s IN ETF=>%s",
    //         _consti.tokenAddress,
    //         await etfC.constitunentsReserves(_consti.tokenAddress)
    //       );
    //       console.log(
    //         "ERC20 %s BALANCE=>",
    //         _consti.tokenAddress,
    //         await _token.balanceOf(etf)
    //       );
    //     }
    //     console.log(
    //       "AFTER  EFT NAV=>",
    //       ethers.formatEther(await ceto.nav(etf, WETH, 10)),
    //       "ETH"
    //     );
    //     console.log(
    //       "USER ETH=>",
    //       ethers.formatEther(await ethers.provider.getBalance(signer1.address))
    //     );
    //   }
}
