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

import {Test} from "forge-std/Test.sol";
import {ISO20022Router} from "@emoney/ISO20022Router.sol";
import {IISO20022Router} from "@emoney/interfaces/IISO20022Router.sol";
import {RailTriggerRegistry} from "@emoney/RailTriggerRegistry.sol";
import {IRailTriggerRegistry} from "@emoney/interfaces/IRailTriggerRegistry.sol";
import {RailTypes} from "@emoney/libraries/RailTypes.sol";
import {ISO20022Types} from "@emoney/libraries/ISO20022Types.sol";

contract ISO20022RouterTest is Test {
    ISO20022Router public router;
    RailTriggerRegistry public triggerRegistry;
    address public admin;
    address public railOperator;
    address public token;

    function setUp() public {
        admin = address(0x1);
        railOperator = address(0x2);
        token = address(0x100);

        triggerRegistry = new RailTriggerRegistry(admin);
        router = new ISO20022Router(admin, address(triggerRegistry));

        vm.startPrank(admin);
        triggerRegistry.grantRole(triggerRegistry.RAIL_OPERATOR_ROLE(), address(router));
        router.grantRole(router.RAIL_OPERATOR_ROLE(), railOperator);
        vm.stopPrank();
    }

    function test_submitOutbound() public {
        IISO20022Router.CanonicalMessage memory m = IISO20022Router.CanonicalMessage({
            msgType: ISO20022Types.PAIN_001,
            instructionId: keccak256("instruction1"),
            endToEndId: keccak256("e2e1"),
            msgId: bytes32(0),
            uetr: bytes32(0),
            accountRefId: keccak256("account1"),
            counterpartyRefId: keccak256("counterparty1"),
            debtorId: bytes32(0),
            creditorId: bytes32(0),
            purpose: bytes32(0),
            settlementMethod: bytes32(0),
            categoryPurpose: bytes32(0),
            token: token,
            amount: 1000,
            currencyCode: keccak256("USD"),
            payloadHash: keccak256("payload1")
        });

        vm.expectEmit(true, true, false, true);
        emit OutboundSubmitted(0, ISO20022Types.PAIN_001, keccak256("instruction1"), keccak256("account1"));

        vm.prank(railOperator);
        uint256 triggerId = router.submitOutbound(m);

        assertEq(triggerId, 0);
        IRailTriggerRegistry.Trigger memory trigger = triggerRegistry.getTrigger(triggerId);
        assertEq(trigger.instructionId, keccak256("instruction1"));
        assertEq(trigger.msgType, ISO20022Types.PAIN_001);
    }

    function test_submitInbound() public {
        IISO20022Router.CanonicalMessage memory m = IISO20022Router.CanonicalMessage({
            msgType: ISO20022Types.CAMT_054,
            instructionId: keccak256("instruction2"),
            endToEndId: keccak256("e2e2"),
            msgId: bytes32(0),
            uetr: bytes32(0),
            accountRefId: keccak256("account2"),
            counterpartyRefId: keccak256("counterparty2"),
            debtorId: bytes32(0),
            creditorId: bytes32(0),
            purpose: bytes32(0),
            settlementMethod: bytes32(0),
            categoryPurpose: bytes32(0),
            token: token,
            amount: 2000,
            currencyCode: keccak256("EUR"),
            payloadHash: keccak256("payload2")
        });

        vm.expectEmit(true, true, false, true);
        emit InboundSubmitted(0, ISO20022Types.CAMT_054, keccak256("instruction2"), keccak256("account2"));

        vm.prank(railOperator);
        uint256 triggerId = router.submitInbound(m);

        assertEq(triggerId, 0);
        IRailTriggerRegistry.Trigger memory trigger = triggerRegistry.getTrigger(triggerId);
        assertEq(trigger.instructionId, keccak256("instruction2"));
        assertEq(trigger.msgType, ISO20022Types.CAMT_054);
    }

    function test_getTriggerIdByInstructionId() public {
        IISO20022Router.CanonicalMessage memory m = IISO20022Router.CanonicalMessage({
            msgType: ISO20022Types.PAIN_001,
            instructionId: keccak256("instruction3"),
            endToEndId: bytes32(0),
            msgId: bytes32(0),
            uetr: bytes32(0),
            accountRefId: keccak256("account3"),
            counterpartyRefId: bytes32(0),
            debtorId: bytes32(0),
            creditorId: bytes32(0),
            purpose: bytes32(0),
            settlementMethod: bytes32(0),
            categoryPurpose: bytes32(0),
            token: token,
            amount: 3000,
            currencyCode: keccak256("USD"),
            payloadHash: bytes32(0)
        });

        vm.prank(railOperator);
        uint256 triggerId = router.submitOutbound(m);

        assertEq(router.getTriggerIdByInstructionId(keccak256("instruction3")), triggerId);
    }
    
    // Helper events for testing (match IISO20022Router events)
    event InboundSubmitted(uint256 indexed triggerId, bytes32 msgType, bytes32 instructionId, bytes32 accountRefId);
    event OutboundSubmitted(uint256 indexed triggerId, bytes32 msgType, bytes32 instructionId, bytes32 accountRefId);
}

