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

import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import "./interfaces/ICoupon.sol";
import "./interfaces/ICouponBatch.sol";
import "./interfaces/ICompliance.sol";

/// @title CouponFactory — 券发行工厂
/// @notice 负责批量铸造券，支持 ERC-721（逐张追踪）和 ERC-1155（同质化批量）双模式
/// @dev 使用 Transparent Proxy 部署，可升级
contract CouponFactory is Initializable, AccessControlUpgradeable, ReentrancyGuardUpgradeable {
    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
    bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");

    ICoupon public couponContract;
    ICouponBatch public couponBatchContract;
    ICompliance public compliance;

    uint256 public nextBatchId;

    // 批次信息
    struct BatchInfo {
        address issuer;
        uint256 faceValue;
        uint256 quantity;
        ICoupon.CouponType couponType;
        uint256 createdAt;
        uint256[] tokenIds;
    }

    mapping(uint256 => BatchInfo) public batches;

    // --- Events ---
    event CouponBatchMinted(
        address indexed issuer,
        uint256 indexed batchId,
        uint256 faceValue,
        uint256 quantity,
        ICoupon.CouponType couponType
    );
    event CouponContractUpdated(address indexed newCouponContract);
    event CouponBatchContractUpdated(address indexed newCouponBatchContract);
    event ComplianceContractUpdated(address indexed newCompliance);
    event CouponBatch1155Minted(
        address indexed issuer,
        uint256 indexed batchId,
        uint256 typeId,
        uint256 faceValue,
        uint256 quantity
    );

    function initialize(
        address _couponContract,
        address _compliance,
        address admin
    ) external initializer {
        __AccessControl_init();
        __ReentrancyGuard_init();

        couponContract = ICoupon(_couponContract);
        compliance = ICompliance(_compliance);

        _grantRole(DEFAULT_ADMIN_ROLE, admin);
        _grantRole(ADMIN_ROLE, admin);
        _grantRole(MINTER_ROLE, admin);
    }

    /// @notice 批量铸造券
    /// @param issuer 发行方地址
    /// @param faceValue 面值（USDC 精度，6位小数）
    /// @param quantity 数量
    /// @param config 券配置
    /// @return tokenIds 铸造的 token ID 数组
    function mintBatch(
        address issuer,
        uint256 faceValue,
        uint256 quantity,
        ICoupon.CouponConfig calldata config
    ) external onlyRole(MINTER_ROLE) nonReentrant returns (uint256[] memory tokenIds) {
        require(issuer != address(0), "CouponFactory: zero address issuer");
        require(faceValue > 0, "CouponFactory: zero face value");
        require(quantity > 0 && quantity <= 10000, "CouponFactory: invalid quantity");

        // Utility Track 强制：价格上限 = 面值，最长12个月
        if (config.couponType == ICoupon.CouponType.Utility) {
            require(config.maxPrice <= faceValue, "Utility: maxPrice <= faceValue");
            require(
                config.expiryDate <= block.timestamp + 365 days,
                "Utility: max 12 months"
            );
            require(config.expiryDate > block.timestamp, "Utility: expiry must be future");
        }

        // Securities Track 强制：必须通过合格投资者验证
        if (config.couponType == ICoupon.CouponType.Security) {
            require(config.expiryDate > 0, "Security: expiry required");
            // 发行方必须 KYC L3
            compliance.requireKycLevel(issuer, 3);
        }

        // 铸造
        tokenIds = new uint256[](quantity);
        ICoupon.CouponConfig memory mintConfig = ICoupon.CouponConfig({
            couponType: config.couponType,
            transferable: config.transferable,
            maxResaleCount: config.maxResaleCount,
            maxPrice: config.maxPrice,
            expiryDate: config.expiryDate,
            minPurchase: config.minPurchase,
            stackable: config.stackable,
            allowedStores: config.allowedStores,
            issuer: issuer,
            faceValue: faceValue
        });

        for (uint256 i = 0; i < quantity; i++) {
            tokenIds[i] = couponContract.mint(issuer, faceValue, mintConfig);
        }

        // 记录批次
        uint256 batchId = nextBatchId++;
        batches[batchId] = BatchInfo({
            issuer: issuer,
            faceValue: faceValue,
            quantity: quantity,
            couponType: config.couponType,
            createdAt: block.timestamp,
            tokenIds: tokenIds
        });

        emit CouponBatchMinted(issuer, batchId, faceValue, quantity, config.couponType);
    }

    /// @notice 查询批次信息
    function getBatchInfo(uint256 batchId) external view returns (BatchInfo memory) {
        return batches[batchId];
    }

    /// @notice 更新 Coupon 合约地址
    function setCouponContract(address _couponContract) external onlyRole(ADMIN_ROLE) {
        require(_couponContract != address(0), "CouponFactory: zero address");
        couponContract = ICoupon(_couponContract);
        emit CouponContractUpdated(_couponContract);
    }

    /// @notice 更新 Compliance 合约地址
    function setComplianceContract(address _compliance) external onlyRole(ADMIN_ROLE) {
        require(_compliance != address(0), "CouponFactory: zero address");
        compliance = ICompliance(_compliance);
        emit ComplianceContractUpdated(_compliance);
    }

    // =====================================================
    // ERC-1155 同质化券铸造（Utility Track 专用）
    // =====================================================

    /// @notice 铸造 ERC-1155 同质化券（Utility Track 专用）
    /// @param issuer 发行方地址
    /// @param faceValue 面值（USDC 精度，6位小数）
    /// @param quantity 数量（上限 100,000，ERC-1155 为 O(1) 铸造）
    /// @param config 券配置
    /// @return typeId ERC-1155 token type ID
    function mintBatch1155(
        address issuer,
        uint256 faceValue,
        uint256 quantity,
        ICouponBatch.BatchCouponConfig calldata config
    ) external onlyRole(MINTER_ROLE) nonReentrant returns (uint256 typeId) {
        require(issuer != address(0), "CouponFactory: zero address issuer");
        require(faceValue > 0, "CouponFactory: zero face value");
        require(quantity > 0 && quantity <= 100000, "CouponFactory: invalid quantity");
        require(
            address(couponBatchContract) != address(0),
            "CouponFactory: batch contract not set"
        );

        // Utility Track 强制（ERC-1155 仅限 Utility）
        require(config.maxPrice <= faceValue, "Utility: maxPrice <= faceValue");
        require(
            config.expiryDate <= block.timestamp + 365 days,
            "Utility: max 12 months"
        );
        require(config.expiryDate > block.timestamp, "Utility: expiry must be future");

        // 通过 CouponBatch 合约铸造
        typeId = couponBatchContract.mint(issuer, faceValue, quantity, config);

        // 记录批次（tokenIds 为空，ERC-1155 使用 typeId + quantity）
        uint256 batchId = nextBatchId++;
        batches[batchId] = BatchInfo({
            issuer: issuer,
            faceValue: faceValue,
            quantity: quantity,
            couponType: ICoupon.CouponType.Utility,
            createdAt: block.timestamp,
            tokenIds: new uint256[](0)
        });

        emit CouponBatch1155Minted(issuer, batchId, typeId, faceValue, quantity);
    }

    /// @notice 设置 CouponBatch (ERC-1155) 合约地址
    function setCouponBatchContract(address _couponBatchContract) external onlyRole(ADMIN_ROLE) {
        require(_couponBatchContract != address(0), "CouponFactory: zero address");
        couponBatchContract = ICouponBatch(_couponBatchContract);
        emit CouponBatchContractUpdated(_couponBatchContract);
    }
}
