// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.24;

/// @title EveryChannelRail
/// @notice Storage-light Ethereum rails for every.channel stream identity, manifest, and
/// transport attestations. The intended deployment target is a private Ethereum-compatible
/// network where iroh remains the transport/control plane and this contract carries compact
/// settlement metadata only.
contract EveryChannelRail {
    struct ManifestPointer {
        bytes32 streamIdHash;
        bytes32 epochIdHash;
        bytes32 manifestId;
        bytes32 bodyCommitment;
        bytes32 dataRoot;
        uint64 createdUnixMs;
        address announcer;
    }

    struct AnnouncementPointer {
        bytes32 streamIdHash;
        bytes32 announcementCommitment;
        uint64 updatedUnixMs;
        uint64 ttlMs;
        address announcer;
    }

    mapping(bytes32 => ManifestPointer) public latestManifestByEpoch;
    mapping(bytes32 => AnnouncementPointer) public latestAnnouncementByStream;

    event ManifestCommitted(
        bytes32 indexed streamIdHash,
        bytes32 indexed epochIdHash,
        bytes32 indexed manifestId,
        bytes32 bodyCommitment,
        bytes32 dataRoot,
        uint64 createdUnixMs,
        address announcer
    );

    event TransportAnnounced(
        bytes32 indexed streamIdHash,
        bytes32 indexed announcementCommitment,
        uint64 updatedUnixMs,
        uint64 ttlMs,
        address announcer
    );

    function commitManifest(
        string calldata streamId,
        string calldata epochId,
        bytes32 manifestId,
        bytes32 bodyCommitment,
        bytes32 dataRoot,
        uint64 createdUnixMs
    ) external {
        bytes32 streamIdHash = keccak256(bytes(streamId));
        bytes32 epochIdHash = keccak256(bytes(epochId));
        bytes32 slot = keccak256(abi.encode(streamIdHash, epochIdHash));

        latestManifestByEpoch[slot] = ManifestPointer({
            streamIdHash: streamIdHash,
            epochIdHash: epochIdHash,
            manifestId: manifestId,
            bodyCommitment: bodyCommitment,
            dataRoot: dataRoot,
            createdUnixMs: createdUnixMs,
            announcer: msg.sender
        });

        emit ManifestCommitted(
            streamIdHash,
            epochIdHash,
            manifestId,
            bodyCommitment,
            dataRoot,
            createdUnixMs,
            msg.sender
        );
    }

    function announceTransport(
        string calldata streamId,
        bytes32 announcementCommitment,
        uint64 updatedUnixMs,
        uint64 ttlMs
    ) external {
        bytes32 streamIdHash = keccak256(bytes(streamId));

        latestAnnouncementByStream[streamIdHash] = AnnouncementPointer({
            streamIdHash: streamIdHash,
            announcementCommitment: announcementCommitment,
            updatedUnixMs: updatedUnixMs,
            ttlMs: ttlMs,
            announcer: msg.sender
        });

        emit TransportAnnounced(
            streamIdHash,
            announcementCommitment,
            updatedUnixMs,
            ttlMs,
            msg.sender
        );
    }
}
