import hashlib
import time
import datetime
import os
import logging
from typing import Optional, Tuple

# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

class VerificationStampGenerator:
    """
    A class for generating and verifying cryptographic verification stamps for files.
    The stamps include a SHA256 hash of the file, a UTC timestamp, and a link to the run report path.
    """

    def __init__(self):
        """
        Initializes the VerificationStampGenerator.
        """
        pass

    def generate_stamp(self, file_path: str, run_report_path: str) -> str:
        """
        Generates a verification stamp for the given file.

        Args:
            file_path (str): The path to the file to be stamped.
            run_report_path (str): The path to the run report associated with the file.

        Returns:
            str: The formatted verification stamp string.

        Raises:
            FileNotFoundError: If the file does not exist.
            OSError: If there is an error reading the file.
        """
        try:
            with open(file_path, "rb") as f:
                file_content = f.read()
        except FileNotFoundError:
            logging.error(f"File not found: {file_path}")
            raise FileNotFoundError(f"File not found: {file_path}")
        except OSError as e:
            logging.error(f"Error reading file: {file_path} - {e}")
            raise OSError(f"Error reading file: {file_path} - {e}")

        sha256_hash = hashlib.sha256(file_content).hexdigest()
        utc_timestamp = datetime.datetime.utcnow().isoformat() + "Z"  # ISO format with 'Z' for UTC

        stamp_string = f"SHA256: {sha256_hash}\nTimestamp (UTC): {utc_timestamp}\nRun Report: {run_report_path}"

        logging.info(f"Generated stamp for file: {file_path}")
        return stamp_string

    def verify_stamp(self, file_path: str, stamp_string: str) -> bool:
        """
        Verifies an existing stamp against the current file content.

        Args:
            file_path (str): The path to the file to be verified.
            stamp_string (str): The verification stamp string to check.

        Returns:
            bool: True if the stamp is valid, False otherwise.
        """
        try:
            # Extract information from the stamp string
            lines = stamp_string.splitlines()
            if len(lines) != 3:
                logging.warning(f"Invalid stamp format for file: {file_path}")
                return False

            expected_hash = lines[0].split(": ")[1]
            expected_timestamp = lines[1].split(": ")[1]  # Not used in verification, but extracted
            expected_run_report_path = lines[2].split(": ")[1]

            # Regenerate the hash of the file
            with open(file_path, "rb") as f:
                file_content = f.read()
            actual_hash = hashlib.sha256(file_content).hexdigest()

            # Compare the hashes
            if actual_hash == expected_hash:
                logging.info(f"Stamp verified successfully for file: {file_path}")
                return True
            else:
                logging.warning(f"Stamp verification failed for file: {file_path}")
                return False

        except FileNotFoundError:
            logging.error(f"File not found: {file_path}")
            return False
        except OSError as e:
            logging.error(f"Error reading file: {file_path} - {e}")
            return False
        except IndexError:
            logging.warning(f"Invalid stamp format for file: {file_path}")
            return False
        except Exception as e:
            logging.error(f"An unexpected error occurred during verification: {e}")
            return False


if __name__ == '__main__':
    # Example usage
    generator = VerificationStampGenerator()
    test_file_path = "test_file.txt"
    run_report_path = "/path/to/run_report.txt"

    # Create a dummy test file
    with open(test_file_path, "w") as f:
        f.write("This is a test file.")

    try:
        # Generate a stamp
        stamp = generator.generate_stamp(test_file_path, run_report_path)
        print("Generated Stamp:\n", stamp)

        # Verify the stamp
        is_valid = generator.verify_stamp(test_file_path, stamp)
        print("Stamp is valid:", is_valid)

        # Modify the file to invalidate the stamp
        with open(test_file_path, "w") as f:
            f.write("This is a modified test file.")

        # Verify the stamp again
        is_valid = generator.verify_stamp(test_file_path, stamp)
        print("Stamp is valid after modification:", is_valid)
    except Exception as e:
        print(f"An error occurred: {e}")
    finally:
        # Clean up the test file
        os.remove(test_file_path)