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

import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";

contract QuantumMaintenanceRecord1155 is ERC1155, AccessControl {
    bytes32 public constant ISSUER_ROLE = keccak256("ISSUER_ROLE");

    struct MaintenanceRecord {
        string publicId;
        string referenceCode;
        string recordHash;
        string traceabilityHash;
        string metadataURI;
        uint256 impactWh;
        uint64 periodStart;
        uint64 periodEnd;
        bool exists;
    }

    string public name = "Quantum Maintenance Record";
    string public symbol = "QMR";
    uint256 public nextTokenId = 1;

    mapping(uint256 => MaintenanceRecord) public records;
    mapping(string => uint256) public tokenIdByPublicId;

    event MaintenanceRecordMinted(
        uint256 indexed tokenId,
        address indexed to,
        string publicId,
        string referenceCode,
        uint256 impactWh
    );

    constructor(address admin, string memory baseURI) ERC1155(baseURI) {
        _grantRole(DEFAULT_ADMIN_ROLE, admin);
        _grantRole(ISSUER_ROLE, admin);
    }

    function mintRecord(
        address to,
        string calldata publicId,
        string calldata referenceCode,
        string calldata recordHash,
        string calldata traceabilityHash,
        string calldata metadataURI,
        uint256 impactWh,
        uint64 periodStart,
        uint64 periodEnd
    ) external onlyRole(ISSUER_ROLE) returns (uint256 tokenId) {
        require(bytes(publicId).length > 0, "publicId required");
        require(bytes(referenceCode).length > 0, "referenceCode required");
        require(bytes(recordHash).length > 0, "recordHash required");
        require(periodEnd > periodStart, "invalid period");
        require(tokenIdByPublicId[publicId] == 0, "publicId already minted");

        tokenId = nextTokenId++;

        records[tokenId] = MaintenanceRecord({
            publicId: publicId,
            referenceCode: referenceCode,
            recordHash: recordHash,
            traceabilityHash: traceabilityHash,
            metadataURI: metadataURI,
            impactWh: impactWh,
            periodStart: periodStart,
            periodEnd: periodEnd,
            exists: true
        });

        tokenIdByPublicId[publicId] = tokenId;
        _mint(to, tokenId, 1, "");

        emit MaintenanceRecordMinted(tokenId, to, publicId, referenceCode, impactWh);
    }

    function uri(uint256 tokenId) public view override returns (string memory) {
        require(records[tokenId].exists, "token does not exist");
        return records[tokenId].metadataURI;
    }
}
