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

/**
 * @title IdentityManagement
 * @dev Smart contract for identity and access management on the blockchain
 */
contract IdentityManagement {
    enum Role {
        ADMIN,
        USER,
        VIEWER
    }

    struct Identity {
        address accountAddress;
        string userId;
        string email;
        string name;
        Role role;
        bool active;
        uint256 createdAt;
        uint256 updatedAt;
    }

    mapping(address => Identity) public identities;
    mapping(string => address) public userIdToAddress;
    address[] public identityAddresses;

    event IdentityCreated(
        address indexed accountAddress,
        string indexed userId,
        Role role,
        uint256 timestamp
    );

    event IdentityUpdated(
        address indexed accountAddress,
        Role newRole,
        uint256 timestamp
    );

    event IdentityDeactivated(
        address indexed accountAddress,
        uint256 timestamp
    );

    /**
     * @dev Create a new identity
     */
    function createIdentity(
        address accountAddress,
        string memory userId,
        string memory email,
        string memory name,
        Role role
    ) public returns (bool) {
        require(identities[accountAddress].accountAddress == address(0), "Identity already exists");
        require(userIdToAddress[userId] == address(0), "User ID already exists");

        identities[accountAddress] = Identity({
            accountAddress: accountAddress,
            userId: userId,
            email: email,
            name: name,
            role: role,
            active: true,
            createdAt: block.timestamp,
            updatedAt: block.timestamp
        });

        userIdToAddress[userId] = accountAddress;
        identityAddresses.push(accountAddress);

        emit IdentityCreated(accountAddress, userId, role, block.timestamp);
        return true;
    }

    /**
     * @dev Update identity role
     */
    function updateIdentityRole(address accountAddress, Role newRole) public {
        require(identities[accountAddress].accountAddress != address(0), "Identity does not exist");
        require(identities[accountAddress].active, "Identity is not active");

        identities[accountAddress].role = newRole;
        identities[accountAddress].updatedAt = block.timestamp;

        emit IdentityUpdated(accountAddress, newRole, block.timestamp);
    }

    /**
     * @dev Deactivate an identity
     */
    function deactivateIdentity(address accountAddress) public {
        require(identities[accountAddress].accountAddress != address(0), "Identity does not exist");
        
        identities[accountAddress].active = false;
        identities[accountAddress].updatedAt = block.timestamp;

        emit IdentityDeactivated(accountAddress, block.timestamp);
    }

    /**
     * @dev Get identity by address
     */
    function getIdentity(address accountAddress) public view returns (Identity memory) {
        require(identities[accountAddress].accountAddress != address(0), "Identity does not exist");
        return identities[accountAddress];
    }

    /**
     * @dev Get identity by user ID
     */
    function getIdentityByUserId(string memory userId) public view returns (Identity memory) {
        address accountAddress = userIdToAddress[userId];
        require(accountAddress != address(0), "User ID not found");
        return identities[accountAddress];
    }

    /**
     * @dev Check if address has role
     */
    function hasRole(address accountAddress, Role role) public view returns (bool) {
        Identity memory identity = identities[accountAddress];
        return identity.active && identity.role == role;
    }
}

