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

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

contract MockUSDC1155 is ERC20 {
    constructor() ERC20("USD Coin", "USDC") {}
    function decimals() public pure override returns (uint8) { return 6; }
    function mint(address to, uint256 amount) external { _mint(to, amount); }
}

/// @title ERC-721 + ERC-1155 混合端到端集成测试
contract Integration1155Test is Test {
    CouponFactory factory;
    Coupon coupon;
    CouponBatch couponBatch;
    Settlement settlement;
    Redemption redemption;
    Redemption1155 redemption1155;
    Compliance compliance;
    MockUSDC1155 usdc;

    address admin = address(1);
    address issuer = address(2);
    address consumer1 = address(3);
    address consumer2 = address(4);

    bytes32 storeA = keccak256("STORE_A");

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

        usdc = new MockUSDC1155();

        // 部署合约
        compliance = new Compliance();
        compliance.initialize(admin);

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

        couponBatch = new CouponBatch();
        couponBatch.initialize("https://genex.io/api/coupon-batch/{id}.json", admin);

        factory = new CouponFactory();
        factory.initialize(address(coupon), address(compliance), admin);

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

        redemption = new Redemption();
        redemption.initialize(address(coupon), address(compliance), admin);

        redemption1155 = new Redemption1155();
        redemption1155.initialize(address(couponBatch), address(compliance), admin);

        // 角色授权
        coupon.grantRole(keccak256("FACTORY_ROLE"), address(factory));
        coupon.grantRole(keccak256("SETTLER_ROLE"), address(settlement));
        coupon.grantRole(keccak256("SETTLER_ROLE"), address(redemption));
        couponBatch.grantRole(keccak256("FACTORY_ROLE"), address(factory));
        couponBatch.grantRole(keccak256("BURNER_ROLE"), address(redemption1155));

        // 关联 CouponBatch
        factory.setCouponBatchContract(address(couponBatch));

        // KYC
        compliance.setKycLevel(issuer, 3);
        compliance.setKycLevel(consumer1, 1);
        compliance.setKycLevel(consumer2, 1);

        // 资金
        usdc.mint(consumer1, 500_000e6);
        usdc.mint(consumer2, 500_000e6);

        vm.stopPrank();

        // Approvals
        vm.prank(consumer1);
        usdc.approve(address(settlement), type(uint256).max);
        vm.prank(consumer1);
        coupon.setApprovalForAll(address(settlement), true);
        vm.prank(issuer);
        coupon.setApprovalForAll(address(settlement), true);
    }

    /// @notice ERC-1155 完整生命周期: Factory铸造 → 分发 → 兑付
    function test_ERC1155FullLifecycle() public {
        // Step 1: 通过 Factory 铸造 ERC-1155 券
        bytes32[] memory stores = new bytes32[](0);
        ICouponBatch.BatchCouponConfig memory batchConfig = ICouponBatch.BatchCouponConfig({
            transferable: true,
            maxPrice: 50e6,
            expiryDate: block.timestamp + 180 days,
            minPurchase: 0,
            stackable: false,
            allowedStores: stores,
            issuer: issuer,
            faceValue: 50e6
        });

        vm.prank(admin);
        uint256 typeId = factory.mintBatch1155(issuer, 50e6, 10000, batchConfig);

        assertEq(couponBatch.balanceOf(issuer, typeId), 10000);
        assertEq(couponBatch.totalSupply(typeId), 10000);

        // Step 2: 发行方分发给消费者
        vm.prank(issuer);
        couponBatch.safeTransferFrom(issuer, consumer1, typeId, 100, "");

        assertEq(couponBatch.balanceOf(consumer1, typeId), 100);
        assertEq(couponBatch.balanceOf(issuer, typeId), 9900);

        // Step 3: 消费者兑付
        vm.prank(consumer1);
        redemption1155.redeem(typeId, 5, storeA);

        assertEq(couponBatch.balanceOf(consumer1, typeId), 95);
        assertEq(couponBatch.totalSupply(typeId), 9995); // 5 已销毁

        Redemption1155.RedemptionRecord memory record = redemption1155.getRedemption(0);
        assertEq(record.consumer, consumer1);
        assertEq(record.amount, 5);
    }

    /// @notice 同一 Factory 同时管理 ERC-721 和 ERC-1155 券
    function test_MixedERC721AndERC1155() public {
        // 铸造 ERC-721 券
        ICoupon.CouponConfig memory config721 = ICoupon.CouponConfig({
            couponType: ICoupon.CouponType.Utility,
            transferable: true,
            maxResaleCount: 3,
            maxPrice: 100e6,
            expiryDate: block.timestamp + 180 days,
            minPurchase: 0,
            stackable: false,
            allowedStores: new bytes32[](0),
            issuer: issuer,
            faceValue: 100e6
        });

        vm.prank(admin);
        uint256[] memory tokenIds = factory.mintBatch(issuer, 100e6, 3, config721);

        // 铸造 ERC-1155 券
        ICouponBatch.BatchCouponConfig memory config1155 = ICouponBatch.BatchCouponConfig({
            transferable: true,
            maxPrice: 50e6,
            expiryDate: block.timestamp + 180 days,
            minPurchase: 0,
            stackable: false,
            allowedStores: new bytes32[](0),
            issuer: issuer,
            faceValue: 50e6
        });

        vm.prank(admin);
        uint256 typeId = factory.mintBatch1155(issuer, 50e6, 5000, config1155);

        // 验证两种标准互不干扰
        assertEq(coupon.ownerOf(tokenIds[0]), issuer);
        assertEq(couponBatch.balanceOf(issuer, typeId), 5000);

        // BatchInfo 共享 nextBatchId 计数器
        CouponFactory.BatchInfo memory batch0 = factory.getBatchInfo(0);
        assertEq(batch0.tokenIds.length, 3); // ERC-721

        CouponFactory.BatchInfo memory batch1 = factory.getBatchInfo(1);
        assertEq(batch1.tokenIds.length, 0); // ERC-1155
        assertEq(batch1.quantity, 5000);
    }

    /// @notice ERC-721 走 Settlement 二级市场，ERC-1155 走 Redemption1155 兑付
    function test_DualTrackSettlementAndRedemption() public {
        // ERC-721: 铸造 + 一级购买 + 兑付
        ICoupon.CouponConfig memory config721 = ICoupon.CouponConfig({
            couponType: ICoupon.CouponType.Utility,
            transferable: true,
            maxResaleCount: 3,
            maxPrice: 100e6,
            expiryDate: block.timestamp + 180 days,
            minPurchase: 0,
            stackable: false,
            allowedStores: new bytes32[](0),
            issuer: issuer,
            faceValue: 100e6
        });

        vm.prank(admin);
        uint256[] memory tokenIds = factory.mintBatch(issuer, 100e6, 1, config721);

        vm.prank(admin);
        settlement.executeSwap(tokenIds[0], consumer1, issuer, 100e6, address(usdc));
        assertEq(coupon.ownerOf(tokenIds[0]), consumer1);

        vm.prank(consumer1);
        redemption.redeem(tokenIds[0], storeA);

        // ERC-1155: 铸造 + 分发 + 兑付
        ICouponBatch.BatchCouponConfig memory config1155 = ICouponBatch.BatchCouponConfig({
            transferable: true,
            maxPrice: 20e6,
            expiryDate: block.timestamp + 90 days,
            minPurchase: 0,
            stackable: true,
            allowedStores: new bytes32[](0),
            issuer: issuer,
            faceValue: 20e6
        });

        vm.prank(admin);
        uint256 typeId = factory.mintBatch1155(issuer, 20e6, 50000, config1155);

        vm.prank(issuer);
        couponBatch.safeTransferFrom(issuer, consumer1, typeId, 200, "");

        vm.prank(consumer1);
        redemption1155.redeem(typeId, 10, storeA);

        assertEq(couponBatch.balanceOf(consumer1, typeId), 190);
    }

    /// @notice 合规系统同时影响两种标准
    function test_ComplianceAffectsBothStandards() public {
        // 铸造 ERC-1155
        ICouponBatch.BatchCouponConfig memory config1155 = ICouponBatch.BatchCouponConfig({
            transferable: true,
            maxPrice: 100e6,
            expiryDate: block.timestamp + 180 days,
            minPurchase: 0,
            stackable: false,
            allowedStores: new bytes32[](0),
            issuer: issuer,
            faceValue: 100e6
        });

        vm.prank(admin);
        uint256 typeId = factory.mintBatch1155(issuer, 100e6, 1000, config1155);

        vm.prank(issuer);
        couponBatch.safeTransferFrom(issuer, consumer1, typeId, 50, "");

        // 将 consumer1 加入黑名单
        vm.prank(admin);
        compliance.addToBlacklist(consumer1, "OFAC");

        // ERC-1155 兑付被拒绝
        vm.prank(consumer1);
        vm.expectRevert("Redemption1155: blacklisted");
        redemption1155.redeem(typeId, 1, storeA);
    }

    /// @notice 非可转让 ERC-1155 券不能转移
    function test_NonTransferableERC1155() public {
        ICouponBatch.BatchCouponConfig memory config = ICouponBatch.BatchCouponConfig({
            transferable: false,
            maxPrice: 30e6,
            expiryDate: block.timestamp + 90 days,
            minPurchase: 0,
            stackable: false,
            allowedStores: new bytes32[](0),
            issuer: issuer,
            faceValue: 30e6
        });

        vm.prank(admin);
        uint256 typeId = factory.mintBatch1155(issuer, 30e6, 1000, config);

        // 不可转让
        vm.prank(issuer);
        vm.expectRevert("CouponBatch: non-transferable");
        couponBatch.safeTransferFrom(issuer, consumer1, typeId, 10, "");

        // 但发行方自己可以兑付（通过 BURNER_ROLE 销毁）
        // — 不过 Redemption1155 检查的是 msg.sender 的 balance
        assertEq(couponBatch.balanceOf(issuer, typeId), 1000);
    }
}
