import logging
import os
import re
from datetime import datetime, timedelta
import variables_test
import time
import json


# Use getattr() to dynamically access the logging level
log_level = getattr(logging, variables_test.DEBUG_LEVEL, logging.INFO)  # Default to logging.INFO if not found

# Set up logging
logging.basicConfig(
    format='%(asctime)s - %(levelname)s - %(message)s',
    level=log_level,
    handlers=[logging.StreamHandler()]  # Logs to console by default
)


def check_alerts(rule_id: str):
    """
    Check the alerts log for the specified rule ID.

    Args:
        rule_id (str): The rule ID to search for in the alerts log. Must be a numeric string.
    """
    logging.info("Running function check_alerts")
    time.sleep(5)  # Wait for the alert to be logged

    # Strip whitespace and validate the input
    rule_id = rule_id.strip()
    if not rule_id.isdigit():
        logging.error("Invalid rule_id: must be a numeric string.")
        raise ValueError("The rule_id must be a numeric string.")


    # Pass the validated rule_id
    parse_rule_id(variables_test.ALERT_LOG_PATH, rule_id)



def extract_time(timestamp: str) -> str:
    """
    Extract the time part from the timestamp.

    Args:
        timestamp (str): The timestamp string.

    Returns:
        str: The extracted time in HH:MM:SS format.
    """
    # Assuming the timestamp is in the format "YYYY-MM-DDTHH:MM:SS.sssZ"
    time_part = timestamp.split('T')[1].split('.')[0]
    return time_part


def get_rule_id(log_file_path: str, rule_id: str) -> dict:
    """
    Get the last log entry for the current date for the provided rule ID.

    Args:
        log_file_path (str): The path to the log file.
        rule_id (str): The rule ID to search for in the log file.

    Returns:
        dict: The parsed log entry as a dictionary if found, otherwise an empty dictionary.
    """
    logging.debug(f"Running function get_rule_id for rule ID {rule_id}")

    # Test if the log file exists and is readable
    if not os.path.isfile(log_file_path):
        logging.error(f"Error: Log file {log_file_path} does not exist or is not accessible.")
        return {}

    # Get today's date dynamically
    today_date = datetime.now().strftime("%Y/%m/%d")

    # Extract the last log entry with the specified rule ID and today's date
    last_log = None
    with open(log_file_path, 'r') as file:
        for line in file:
            alert = json.loads(line)
            if alert.get("rule", {}).get("id") == rule_id:
                last_log = line

    # Check if the log entry is found
    if not last_log:
        logging.warning(f"Warning: No logs found for Rule ID {rule_id} on {today_date}.")
        return {}

    # Parse the JSON-like string to extract the required information
    alert = json.loads(last_log)
    return alert



def check_fim_change(dir: str):
    """
    Check if the specified directory was modified regarding rule ID 550.

    Args:
        dir (str): The directory to check.
    """
    logging.debug(f"Checking if directory '{dir}' was modified regarding rule ID 550.")
    time.sleep(5)  # Wait for the alert to be logged
    
    # NOTE : Ensure no whitespace in dir paths 

    # Remove whitespace from the directory argument
    dir = dir.strip().replace(" ", "")
    # Get the last log entry for rule ID 550
    alert = get_rule_id(variables_test.ALERT_LOG_PATH, "550")

    if alert:
        # Extract the path from the alert
        path = alert.get("syscheck", {}).get("path")

        # Check if the path matches the specified directory
        if dir in path:
            logging.info(f"Directory '{dir}' was modified as per rule ID 550. It occured at file {path}.")
    
            # Additional checks can be added here
        else:
            logging.warning(f"Directory '{dir}' was not modified as per rule ID 550.")
    else:
        logging.warning(f"No alert found for rule ID 550.")

def is_time_consistent(log_time: str, max_delay: int = 300) -> bool:
    """
    Compare the time of the log retrieval and the actual time.

    Args:
        log_time (str): The time of the log retrieval in HH:MM:SS format.
        max_delay (int): The maximum allowed delay in seconds. Default is 300 seconds (5 minutes).

    Returns:
        bool: True if the time difference is within the allowed delay, False otherwise.
    """
    logging.debug(f"Checking time consistency for log time {log_time} with max delay {max_delay} seconds.")

    # Get the current time in HH:MM:SS format
    current_time = datetime.now().strftime("%H:%M:%S")

    # Convert both times to seconds since the start of the day for comparison
    log_seconds = int(datetime.strptime(log_time, "%H:%M:%S").strftime("%s"))
    current_seconds = int(datetime.strptime(current_time, "%H:%M:%S").strftime("%s"))

    # Calculate the difference in seconds
    time_difference = current_seconds - log_seconds

    # Check if the difference is less than the allowed delay
    if time_difference < max_delay:
        logging.info(f"The log time is less than {max_delay} seconds ago: {time_difference} seconds")
        return True
    else:
        logging.warning(f"Warning: The log time is more than {max_delay} seconds ago: {time_difference} seconds")
        return False
    

def parse_rule_id(log_file_path: str, rule_id: str):
    """
    Parse the log file to extract information based on the rule ID.

    Args:
        log_file_path (str): The path to the log file.
        rule_id (str): The rule ID to search for in the log file.

    Returns:
        None
    """
    logging.debug(f"Running function parse_rule_id for rule ID {rule_id}")

    # Get the last log entry for the rule ID
    alert = get_rule_id(log_file_path, rule_id)

    if alert:
        # Extract required fields
        active_response = alert.get("decoder", {}).get("name")
        agent_id = alert.get("agent", {}).get("id")
        technique = alert.get("rule", {}).get("mitre", {}).get("technique", [None])[0]
        frequency = alert.get("rule", {}).get("firedtimes")
        log_timestamp = alert.get("timestamp")

        # Check if all required fields are extracted
        if not all([active_response, agent_id, technique, frequency]):
            logging.warning("Warning: Failed to extract some fields from the log entry.")
            return

        # Extract time from the log timestamp
        log_time = extract_time(log_timestamp)

        # Log the time of last log retrieval and any delay
        logging.info(f"Last log retrieved at time: {log_time}")

        # Log the extracted details
        if active_response:
            logging.info(f"Active Response: {active_response}")
        else:
            logging.warning("Active Response: Not available")

        if agent_id:
            logging.info(f"Agent ID: {agent_id}")
        else:
            logging.warning("Agent ID: Not available")

        if technique:
            logging.info(f"Attack Technique: {technique}")
        else:
            logging.warning("Attack Technique: Not available")

        if frequency:
            logging.info(f"Frequency: {frequency}")
        else:
            logging.warning("Frequency: Not available")

        # Check time consistency
        is_time_consistent(log_time)
    else:
        logging.warning(f"No alert found for rule ID {rule_id}.")