from sympy.core.sympify import sympify
from sympy.logic.boolalg import Implies, And, Or, truth_table

def get_contrapositive(expression):
    """
    Returns the contrapositive of a logical implication.
    If input is P -> Q, output is ~Q -> ~P.
    """
    try:
        expr = sympify(expression)
        if isinstance(expr, Implies):
            p, q = expr.args
            return Implies(~q, ~p)
        else:
            raise ValueError("Expression must be an implication (e.g., 'P >> Q')")
    except Exception as e:
        raise ValueError(f"Error processing expression: {e}")

def get_conjunction(expr1, expr2):
    """
    Returns the logical AND (conjunction) of two expressions.
    """
    return And(sympify(expr1), sympify(expr2))

def get_disjunction(expr1, expr2):
    """
    Returns the logical OR (disjunction) of two expressions.
    """
    return Or(sympify(expr1), sympify(expr2))

def get_formatted_truth_table(expression):
    """
    Generates a string representation of the truth table for any expression.
    """
    expr = sympify(expression)
    # Get all unique variables in the expression and sort them alphabetically
    vars_list = sorted(list(expr.free_symbols), key=lambda s: s.name)
    
    # Create the top header row (e.g., P | Q | Result)
    header = " | ".join([str(v) for v in vars_list]) + " | Result"
    separator = "-" * len(header)
    
    table_rows = [header, separator]
    
    # Generate the truth table data
    table = truth_table(expr, vars_list)
    
    # Loop through the inputs and the final result
    for inputs, result_val in table:
        # Format the inputs (T or F)
        formatted_inputs = " | ".join(["T" if val else "F" for val in inputs])
        # Format the result (T or F)
        result = "T" if result_val else "F"
        
        # Add the row to our list
        table_rows.append(f"{formatted_inputs} | {result}")
        
    # Join all rows with a newline character so it prints nicely
    return "\n".join(table_rows)