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

import "./FlightConfirmation.sol";

/**
 * @title Signature Verification System
 * @dev A contract for verifying digital signatures from multiple parties
 */
contract SignatureVerification {
    // Event emitted when a signature is verified
    event SignatureVerified(
        bytes32 indexed flightId,
        address signer,
        uint8 partyType, // 0: Manufacturer, 1: Logistics Provider, 2: Buyer
        bytes32 messageHash
    );

    /**
     * @dev Verifies an ECDSA signature
     * @param _message The original message that was signed
     * @param _signature The signature to verify
     * @return signer The address that signed the message
     */
    function recoverSigner(bytes32 _message, bytes memory _signature) 
        internal 
        pure 
        returns (address signer) 
    {
        require(_signature.length == 65, "Invalid signature length");
        
        bytes32 r;
        bytes32 s;
        uint8 v;
        
        assembly {
            r := mload(add(_signature, 32))
            s := mload(add(_signature, 64))
            v := byte(0, mload(add(_signature, 96)))
        }
        
        // Adjust v value if needed
        if (v < 27) {
            v += 27;
        }
        
        require(v == 27 || v == 28, "Invalid v value");
        
        signer = ecrecover(_message, v, r, s);
        require(signer != address(0), "ECDSA: Invalid signature");
    }

    /**
     * @dev Verifies a signature for a specific party type for a flight
     * @param _flightId Unique identifier for the flight
     * @param _partyType Type of the party (0: Manufacturer, 1: Logistics, 2: Buyer)
     * @param _message The message to verify
     * @param _signature The signature to verify
     * @return isValid Whether the signature is valid
     * @return recoveredSigner The address of the signer
     */
    function verifyFlightSignature(
        bytes32 _flightId,
        uint8 _partyType,
        bytes32 _message,
        bytes memory _signature
    ) 
        public 
        pure 
        returns (bool isValid, address recoveredSigner) 
    {
        recoveredSigner = recoverSigner(_message, _signature);
        isValid = recoveredSigner != address(0);
        
        emit SignatureVerified(_flightId, recoveredSigner, _partyType, _message);
    }

    /**
     * @dev Creates a hash for the flight confirmation message
     * @param _flightId Unique identifier for the flight
     * @param _signer Address of the signer
     * @param _partyType Type of the party (0: Manufacturer, 1: Logistics, 2: Buyer)
     * @param _timestamp Timestamp of the confirmation
     * @return Hash of the message
     */
    function createFlightConfirmationHash(
        bytes32 _flightId,
        address _signer,
        uint8 _partyType,
        uint256 _timestamp
    ) 
        public 
        pure 
        returns (bytes32) 
    {
        return keccak256(
            abi.encodePacked(
                "\x19Ethereum Signed Message:\n32",
                keccak256(
                    abi.encodePacked(
                        "Flight Confirmation",
                        _flightId,
                        _signer,
                        _partyType,
                        _timestamp
                    )
                )
            )
        );
    }

    /**
     * @dev Convenience function to verify and process a flight confirmation
     * @param _flightId Unique identifier for the flight
     * @param _partyType Type of the party (0: Manufacturer, 1: Logistics, 2: Buyer)
     * @param _timestamp Timestamp of the confirmation
     * @param _signature The signature to verify
     * @return isValid Whether the signature is valid
     * @return recoveredSigner The address of the signer
     */
    function processFlightConfirmation(
        bytes32 _flightId,
        uint8 _partyType,
        uint256 _timestamp,
        bytes memory _signature
    ) 
        public 
        view 
        returns (bool isValid, address recoveredSigner) 
    {
        bytes32 messageHash = createFlightConfirmationHash(
            _flightId,
            msg.sender,
            _partyType,
            _timestamp
        );
        
        return verifyFlightSignature(_flightId, _partyType, messageHash, _signature);
    }
}