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

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";

interface IPancakeRouter {
    function getAmountsOut(uint256 amountIn, address[] calldata path)
        external
        view
        returns (uint256[] memory amounts);

    function addLiquidity(
        address tokenA,
        address tokenB,
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    )
        external
        returns (
            uint256 amountA,
            uint256 amountB,
            uint256 liquidity
        );

    function swapExactTokensForTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);
}

interface IPancakePair {
    function balanceOf(address owner) external view returns (uint256);

    function transfer(address to, uint256 value) external returns (bool);
}

contract BossToken is ERC20, Ownable {
    using SafeMath for uint256;
    mapping(address => uint256) private userTokenBalance; // 用户Token余额
    mapping(address => uint256) private partnerBalance; // 合伙人分红余额
    mapping(address => uint256) private nodesBalance; // 节点分红余额
    mapping(address => uint256) private partnerTradeBalance; // 合伙人分红余额
    mapping(address => uint256) private nodesTradeBalance; // 节点交易分红余额
    mapping(address => uint256) private lpTradeBalance; // lp分红

    //address private constant usdtAddress =0x66E972502A34A625828C544a1914E8D8cc2A9dE5; // USDT测试网地址
    address private constant usdtAddress = 0x55d398326f99059fF775485246999027B3197955; // USDT主网地址
    //address private constant routerAddress = 0xD99D1c33F9fC3444f8101754aBC46c52416550D1; // PancakeSwap测试网路由地址
    address private constant routerAddress = 0x10ED43C718714eb63d5aA57B78B54704E256024E; //  PancakeSwap主网路由地址
    address private constant marketManagmentAddress =
        0xbD96088c41a19B00eB1D68B2d46ac5b216329278; // 市值管理
    address private constant operationAddress =
        0x7d8e5f0d71AF3279DB70fBfE8DCF41eD2e665A5F; // 运营地址
    address private constant miningRigAddress =
        0x7cC64971D7C1697164268fF3F41C542891928F2D; // 实体矿机地址
    address private constant partnerAddress =
        0x183c42C4bfccEBAC930931afbd643f36B9cF81f9; // 合伙人分红地址
    address private constant normalNodeAddress =
        0xBb2DD5D00935546F270bDFae9f42FfA5f5164Cd6; // 节点入金分红地址
    address private constant middleNodeAddress =
        0x50877E7117d86faD2E29c6C10fA09Feb34381955; // 超级节点分红地址
    address private constant highNodeAddress =
        0xa414ebb40b94EEe1F05D194f13653FeF2D625F77; // 创世节点分红地址
    address private constant operationTradeAddress =
        0xb10d8f81Dce250092dccb222b40C50630213566C; // 运营交易分红地址
    address private constant partnerTradeAddress =
        0xA55b4fAcB9cC31088E58CB04a27957329c39E1Ed; // 合伙人交易分红地址
    address private constant nodeTradeAddress =
        0x133675E31BD8D975564eBC221B6667D531c6C785; // 节点交易分红地址

    address private constant blackholeAddress = 0x000000000000000000000000000000000000dEaD; // 黑洞地址
    address private constant lpBonusAddress = 0x55EEdab0729Dc4e1e385E746fc475e721Db835ce;
    address private poolAddress; // 池子地址

    uint256 private marketPercent = 10; // 市值管理基点
    uint256 private miningRigPercent = 5; // 矿机基点
    uint256 private communityPercent = 5; // 社区基点
    uint256 private partnerPercent = 2; // 合伙人交易分红基点
    uint256 private nodePercent = 2; // 节点交易分红基点
    uint256 private operationPercent = 1; // 运营交易分红基点

    struct Node {
        address _address;
        uint256 _level;
    }


    address[] private partners; // 合伙人地址
    Node[] private nodes; // 节点地址

    IERC20 private usdt = IERC20(usdtAddress);
    IPancakeRouter public router = IPancakeRouter(routerAddress);

    constructor() ERC20("Boss", "Boss") Ownable(msg.sender) {
        // 初始化代币供应量为 888,999
        uint256 initialSupply = 888999 * 10**decimals();
        _mint(msg.sender, initialSupply);
    }

    // 查询用户
    function QueryUser(address _address)
    
        external
        view
        returns (
            uint256 _tokenBalance,
            uint256 _partnerBalance,
            uint256 _partnerTradeBalance,
            uint256 _nodeBalance,
            uint256 _nodeTradeBalance,
            uint256 _lpTradeBalance
        )
    {
        return (
            userTokenBalance[_address],
            partnerBalance[_address],
            partnerTradeBalance[_address],
            nodesBalance[_address],
            nodesTradeBalance[_address],
            lpTradeBalance[_address]
        );
    }

    // 增加用户Token余额
    function AddToken(address _address, uint256 _amount) external onlyOwner {
        userTokenBalance[_address] = userTokenBalance[_address] + _amount;
        uint256 appp = 111222;
    }

    // 增加用户USDT余额
    function AddBonus(
        address _address,
        uint256 _status,
        uint256 _amount
    ) public onlyOwner {
        if (_status == 1){
            partnerBalance[_address] = partnerBalance[_address] + _amount;
        }

        if (_status == 2){
            nodesBalance[_address] = nodesBalance[_address] + _amount;
        }
    }

    // 分底池里面比到钱包
    function AddPartner(address _address) public onlyOwner {
        bool ok;
        for (uint256 i = 0; i < partners.length; i++) {
            if (partners[i] == _address) {
                ok = true;
            }
        }
        if (!ok) {
            partners.push(_address);
        }
    }

    function GetPartners() external view returns (address[] memory _partners) {
        return partners;
    }

    function AddNodes(address _address, uint256 _level) public onlyOwner {
        bool ok;
        for (uint256 i = 0; i < nodes.length; i++) {
            if (nodes[i]._address == _address) {
                ok = true;
                nodes[i]._level = _level;
            }
        }
        if (!ok) {
            nodes.push(Node(_address, _level));
        }
    }

    function GetNodes() external view returns (Node[] memory _nodes) {
        return nodes;
    }

    // 入金
    function GenerateOrder(address _address, uint256 _amount) public {
        uint256 balance = usdt.allowance(_address, address(this));
        require(balance >= _amount, "USDT not enough");
        bool ok = usdt.transferFrom(_address, address(this), _amount);
        require(ok, "USDT transfer failed");
        generateBonus(_amount);

        // 计算35%的USDT金额用于购买token
        uint256 buyAmount = _amount.mul(35).div(100);

        // 购买token
        buyToken(buyAmount); 
        buyLPToken(buyAmount);

        uint256 liquidityAmount = _amount.mul(35).div(100);
        // 添加流动性
        addLiquidityAndBurnLP(liquidityAmount);
    }

    function buyToken(uint256 usdtAmount) internal {
        // 授权Router使用USDT
        usdt.approve(routerAddress, usdtAmount);
        // 设置交易路径
        address[] memory path = new address[](2);
        path[0] = usdtAddress;
        path[1] = address(this);

        // 先计算出预期可以得到的最小token数量
        uint256[] memory amounts = router.getAmountsOut(usdtAmount, path);
        uint256 minTokenAmount = amounts[1].mul(60).div(100); // 允许 5% 滑点

        // 执行兑换,接收到合约地址
        router.swapExactTokensForTokens(
            usdtAmount,
            minTokenAmount, // 设置最小获得数量
            path,
            owner(), // 接收到合约地址
            block.timestamp + 300
        );
    }
 
    // 添加流动行
    function addLiquidityAndBurnLP(uint256 usdtAmount) internal {
        // 授权Router使用USDT
        usdt.approve(routerAddress, usdtAmount);

        // 计算等值的token数量
        address[] memory path = new address[](2);
        path[0] = usdtAddress;
        path[1] = address(this);
        uint256[] memory amounts = router.getAmountsOut(usdtAmount, path);
        uint256 tokenAmount = amounts[1];
        // 检查合约token余额
        uint256 contractBalance = balanceOf(address(this));
        // 
        require(contractBalance >= tokenAmount, "Insufficient token balance");

        // 授权Router使用token
        _approve(address(this), routerAddress, tokenAmount);

        // 添加流动性
        router.addLiquidity(
            usdtAddress,
            address(this),
            usdtAmount,
            tokenAmount,
            usdtAmount.mul(60).div(100), // 允许10%的滑点
            tokenAmount.mul(60).div(100), // 允许10%的滑点
            address(this), // LP先到合约
            block.timestamp + 300
        );

        // 转移LP到黑洞地址
        IPancakePair lpToken = IPancakePair(poolAddress);
        uint256 lpBalance = lpToken.balanceOf(address(this));
        require(
            lpToken.transfer(blackholeAddress, lpBalance),
            "LP transfer failed"
        );
    }
    
    // 生成奖金
    function generateBonus(uint256 _amount) internal {
        uint256 marketBonus = _amount.mul(10).div(100);
        usdt.transfer(marketManagmentAddress, marketBonus);
        uint256 miningRigBonus = _amount.mul(5).div(100);
        usdt.transfer(miningRigAddress, miningRigBonus);
        uint256 communityBonus = _amount.mul(5).div(100);
        usdt.transfer(operationAddress, communityBonus);
        uint256 normalNodeBonus = _amount.mul(5).div(100);
        usdt.transfer(normalNodeAddress, normalNodeBonus);
        uint256 middleNodeBonus = _amount.mul(2).div(100);
        usdt.transfer(middleNodeAddress, middleNodeBonus);
        uint256 highNodeBonus = _amount.mul(1).div(100);
        usdt.transfer(highNodeAddress, highNodeBonus);
        uint256 partnerBonus = _amount.mul(2).div(100);
        usdt.transfer(partnerAddress, partnerBonus);
    }


    // 喊他们进去喝茶


    // Token提现 
    function WithdrawToken(uint256 _status) external {
        uint256 balance;
        uint256 contractBalance;
        if (_status == 1) {
            uint256 tokenBalance = userTokenBalance[msg.sender];
            require(tokenBalance > 0, "Balance not Enough");
            // 更新用户的Token余额
            userTokenBalance[msg.sender] = 0;
            // 转账操作
            _transfer(address(this), msg.sender, tokenBalance);
            return;
        }

        if (_status == 2) {
            balance = partnerTradeBalance[msg.sender];
            require(balance > 0, "Insufficient BOSS balance");
            contractBalance = balanceOf(partnerTradeAddress);
            require(
                contractBalance >= balance,
                "Partner has insufficient BOSS"
            );
            partnerTradeBalance[msg.sender] = 0;
            bool ok = transferFrom(partnerTradeAddress, msg.sender, balance);
            require(ok, "BOSS transfer failed");
            return;
        }

        if (_status == 3) {
            balance = nodesTradeBalance[msg.sender];
            require(balance > 0, "Insufficient BOSS balance");
            contractBalance = balanceOf(nodeTradeAddress);
            require(contractBalance >= balance, "Node has insufficient BOSS");
            nodesTradeBalance[msg.sender] = 0;
            bool ok = transferFrom(nodeTradeAddress, msg.sender, balance);
            require(ok, "BOSS transfer failed");
            return;
        }

        if (_status == 4){
            uint256 tokenBalance = lpTradeBalance[msg.sender];
            require(tokenBalance > 0, "Balance not Enough");
            // 更新用户的Token余额
            lpTradeBalance[msg.sender] = 0;
            // 转账操作
            _transfer(address(this), msg.sender, tokenBalance);
            return;
        }
    }


    //USDT提现
    function WithdrawBonus(uint256 _status) external {
        // 获取用户的USDT余额
        uint256 balance;
        uint256 contractUsdtBalance;
        if (_status == 1) {
            balance = partnerBalance[msg.sender];
            require(balance > 0, "Insufficient USDT balance");
            contractUsdtBalance = usdt.balanceOf(partnerAddress);
            require(
                contractUsdtBalance >= balance,
                "Partner has insufficient USDT"
            );
            partnerBalance[msg.sender] = 0;
            bool ok = usdt.transferFrom(partnerAddress, msg.sender, balance);
            require(ok, "USDT transfer failed");
            return;
        }

        if (_status == 2) {
            balance = nodesBalance[msg.sender];
            require(balance > 0, "Insufficient USDT balance");
            address levelPoolAddress;
            for (uint256 i = 0; i < nodes.length; i++) {
                if (nodes[i]._address == msg.sender) {
                    if (nodes[i]._level == 1) {
                        contractUsdtBalance = usdt.balanceOf(normalNodeAddress);
                        levelPoolAddress = normalNodeAddress;
                    }

                    if (nodes[i]._level == 2) {
                        contractUsdtBalance = usdt.balanceOf(middleNodeAddress);
                        levelPoolAddress = middleNodeAddress;
                    }

                    if (nodes[i]._level == 3) {
                        contractUsdtBalance = usdt.balanceOf(highNodeAddress);
                        levelPoolAddress = highNodeAddress;
                    }
                }
            }
            require(
                contractUsdtBalance >= balance,
                "Nodes has insufficient USDT"
            );
            nodesBalance[msg.sender] = 0;
            bool ok = usdt.transferFrom(levelPoolAddress, msg.sender, balance);
            require(ok, "USDT transfer failed");
            return;
        }
    }

    // 设置池子地址
    function SetPoolAddress(address _address) external onlyOwner {
        poolAddress = _address;
    }

    // 查询token外部价格
    function QueryTokenPrice() public view returns (uint256 price) {
        address[] memory path = new address[](2);
        path[0] = address(this); // Token 地址
        path[1] = usdtAddress; // USDT 地址
        // 获取兑换结果
        uint256 amountIn = 1e18;
        uint256[] memory amounts = router.getAmountsOut(amountIn, path);
        return amounts[1]; // 返回兑换出的 USDT 数量
    }

    // 重构转账函数
    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual override {
        // 如果转出或转入poolAddress,执行手续费逻辑
        if (from == poolAddress) {
            uint256 price = QueryTokenPrice();
            //低于5000打入黑洞
            if (price.div(1e18) < 5000 && to != address(this)) {
                return;
            }
            uint256 feeAmount = amount.mul(4).div(100);
            uint256 transferAmount = amount.sub(feeAmount);

            super._transfer(from, to, transferAmount);

            uint256 partnerAmount = amount.mul(1).div(100);
            generatePartnerTradeBonus(partnerAmount);
            super._transfer(from,partnerTradeAddress, partnerAmount);

            uint256 nodeAmount = amount.mul(2).div(100);
            generateNodesTradeBonus(nodeAmount);
            super._transfer(from,nodeTradeAddress, nodeAmount);

            uint256 operationAmount = amount.mul(1).div(100);
            super._transfer(from,operationTradeAddress, operationAmount);
            return;
        }

        if (
            to == poolAddress &&
            from != address(this)
        ) {
            uint256 feeAmount = amount.mul(8).div(100);
            uint256 transferAmount = amount.sub(feeAmount);

            super._transfer(from, to, transferAmount);

            // 合伙人交易分红
            uint256 partnerAmount = amount.mul(1).div(100);
            generatePartnerTradeBonus(partnerAmount);
            super._transfer(from, partnerTradeAddress, partnerAmount);

            // 交易节点分红
            uint256 nodeAmount = amount.mul(2).div(100);
            generateNodesTradeBonus(nodeAmount);
            super._transfer(from,nodeTradeAddress, nodeAmount);

            // 运营交易分红
            uint256 operationAmount = amount.mul(1).div(100);
            super._transfer(from,operationTradeAddress, operationAmount);

            // 黑洞销毁
            uint256 destoryAmount = amount.mul(2).div(100);
            super._transfer(from,blackholeAddress, destoryAmount);

            // lp分红
            uint256 lpAmount = amount.mul(2).div(100);
            super._transfer(from,lpBonusAddress, lpAmount);
            return;
        }
        super._transfer(from, to, amount);
    }

    function generatePartnerTradeBonus(uint256 _amount) private {
        if (partners.length == 0){
            return;
        }
        uint256 bonus = _amount.div(partners.length);
        for (uint256 i = 0; i < partners.length; i++) {
            partnerTradeBalance[partners[i]] = partnerTradeBalance[partners[i]] + bonus;
        }
    }

    function generateNodesTradeBonus(uint256 _amount) private {
        if (nodes.length == 0){
            return;
        }
        uint256 bonus = _amount.div(nodes.length);
        for (uint256 i = 0; i < nodes.length; i++) {
            nodesTradeBalance[nodes[i]._address] =
                nodesTradeBalance[nodes[i]._address] +
                bonus;
        }
    }
}