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

import "forge-std/Test.sol";
import "../src/Settlement.sol";
import "../src/Coupon.sol";
import "../src/Compliance.sol";
import "../src/interfaces/ICoupon.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract MockUSDC is ERC20 {
    constructor() ERC20("USD Coin", "USDC") {
        _mint(msg.sender, 1_000_000e6);
    }

    function decimals() public pure override returns (uint8) {
        return 6;
    }

    function mint(address to, uint256 amount) external {
        _mint(to, amount);
    }
}

contract SettlementTest is Test {
    Settlement settlement;
    Coupon coupon;
    Compliance compliance;
    MockUSDC usdc;
    MockUSDC usdt;

    address admin = address(1);
    address buyer = address(4);
    address seller = address(5);

    function setUp() public {
        vm.startPrank(admin);

        usdc = new MockUSDC();
        usdt = new MockUSDC();

        compliance = new Compliance();
        compliance.initialize(admin);

        coupon = new Coupon();
        coupon.initialize("Genex Coupon", "GXC", admin);

        settlement = new Settlement();
        settlement.initialize(address(coupon), address(compliance), address(usdc), admin);

        // 授权
        coupon.grantRole(keccak256("FACTORY_ROLE"), admin);
        coupon.grantRole(keccak256("SETTLER_ROLE"), address(settlement));

        // KYC
        compliance.setKycLevel(buyer, 1);
        compliance.setKycLevel(seller, 1);

        // 给买方 USDC
        usdc.mint(buyer, 1000e6);

        vm.stopPrank();

        // Buyer approve settlement
        vm.prank(buyer);
        usdc.approve(address(settlement), type(uint256).max);

        // Seller approve coupon to settlement
        vm.prank(seller);
        coupon.setApprovalForAll(address(settlement), true);
    }

    function test_AtomicSwapSuccess() public {
        uint256 tokenId = _mintCouponToSeller(100e6);

        vm.prank(admin);
        settlement.executeSwap(tokenId, buyer, seller, 85e6, address(usdc));

        assertEq(coupon.ownerOf(tokenId), buyer);
        assertEq(usdc.balanceOf(seller), 85e6);
    }

    function test_UtilityCannotExceedMaxPrice() public {
        uint256 tokenId = _mintCouponToSeller(100e6);

        vm.prank(admin);
        vm.expectRevert("Utility: price exceeds max price");
        settlement.executeSwap(tokenId, buyer, seller, 110e6, address(usdc));
    }

    function test_RefundReverseSwap() public {
        uint256 tokenId = _mintCouponToSeller(100e6);

        // 先正常交易
        vm.prank(admin);
        settlement.executeSwap(tokenId, buyer, seller, 85e6, address(usdc));

        // Seller 退 USDC approve
        vm.prank(seller);
        usdc.approve(address(settlement), type(uint256).max);
        // Buyer approve coupon
        vm.prank(buyer);
        coupon.setApprovalForAll(address(settlement), true);

        // 退款
        vm.prank(admin);
        settlement.executeRefund(tokenId, buyer, seller, 85e6, address(usdc));

        assertEq(coupon.ownerOf(tokenId), seller);
    }

    function test_BlacklistedBuyerReverts() public {
        uint256 tokenId = _mintCouponToSeller(100e6);

        vm.prank(admin);
        compliance.addToBlacklist(buyer, "OFAC");

        vm.prank(admin);
        vm.expectRevert("Compliance: buyer blacklisted");
        settlement.executeSwap(tokenId, buyer, seller, 85e6, address(usdc));
    }

    function test_MaxResaleCountBlocks() public {
        uint256 tokenId = _mintCouponToSeller(100e6);

        // 交易 3 次达到上限
        for (uint256 i = 0; i < 3; i++) {
            vm.prank(admin);
            settlement.executeSwap(tokenId, buyer, seller, 50e6, address(usdc));

            // Reset: transfer back + fund buyer (skip after last iteration
            // because resaleCount == maxResaleCount and P2P transfer would fail)
            if (i < 2) {
                vm.prank(buyer);
                coupon.safeTransferFrom(buyer, seller, tokenId);
                vm.prank(admin);
                usdc.mint(buyer, 50e6);
            }
        }

        // 第 4 次应失败
        vm.prank(admin);
        vm.expectRevert("Settlement: max resale count exceeded");
        settlement.executeSwap(tokenId, buyer, seller, 50e6, address(usdc));
    }

    function test_ExpiredCouponReverts() public {
        uint256 tokenId = _mintCouponToSeller(100e6);

        // 快进到过期
        vm.warp(block.timestamp + 200 days);

        vm.prank(admin);
        vm.expectRevert("Settlement: coupon expired");
        settlement.executeSwap(tokenId, buyer, seller, 85e6, address(usdc));
    }

    function test_UnsupportedStablecoinReverts() public {
        uint256 tokenId = _mintCouponToSeller(100e6);

        vm.prank(admin);
        vm.expectRevert("Settlement: unsupported stablecoin");
        settlement.executeSwap(tokenId, buyer, seller, 85e6, address(usdt));
    }

    function test_AddStablecoin() public {
        vm.prank(admin);
        settlement.addStablecoin(address(usdt));
        assertTrue(settlement.supportedStablecoins(address(usdt)));
    }

    // --- Helpers ---

    function _mintCouponToSeller(uint256 faceValue) internal returns (uint256) {
        bytes32[] memory stores = new bytes32[](0);
        ICoupon.CouponConfig memory config = ICoupon.CouponConfig({
            couponType: ICoupon.CouponType.Utility,
            transferable: true,
            maxResaleCount: 3,
            maxPrice: faceValue,
            expiryDate: block.timestamp + 180 days,
            minPurchase: 0,
            stackable: false,
            allowedStores: stores,
            issuer: admin,
            faceValue: faceValue
        });

        vm.prank(admin);
        return coupon.mint(seller, faceValue, config);
    }
}
