import logging

_logger = logging.getLogger(__name__)


class MathScorer:
    """Score mathematical question types using SymPy."""

    @staticmethod
    def score_numerical(student_answer, correct_answer):
        """Score a numerical answer with tolerance.
        correct_answer: {"value": float, "tolerance": float}
        """
        try:
            student_val = float(student_answer)
            correct_val = float(correct_answer.get('value', 0))
            tolerance = float(correct_answer.get('tolerance', 0.01))

            correct = abs(student_val - correct_val) <= tolerance
            return {
                'correct': correct,
                'score': 1.0 if correct else 0.0,
                'feedback': 'Correct!' if correct else f'Expected {correct_val} (±{tolerance}), got {student_val}',
            }
        except (ValueError, TypeError) as e:
            return {'correct': False, 'score': 0.0, 'feedback': f'Invalid numerical input: {e}'}

    @staticmethod
    def score_expression(student_expr, correct_expr):
        """Score mathematical expressions using symbolic equivalence."""
        try:
            import sympy
            student_sym = sympy.sympify(student_expr, evaluate=True)
            correct_sym = sympy.sympify(correct_expr, evaluate=True)

            diff = sympy.simplify(student_sym - correct_sym)
            correct = diff == 0 or sympy.simplify(diff).is_zero

            if not correct:
                try:
                    student_float = float(student_sym.evalf())
                    correct_float = float(correct_sym.evalf())
                    correct = abs(student_float - correct_float) < 1e-6
                except Exception:
                    pass

            return {
                'correct': correct,
                'score': 1.0 if correct else 0.0,
                'feedback': 'Correct!' if correct else f'Your answer {student_expr} is not equivalent to {correct_expr}',
                'simplified_student': str(sympy.simplify(student_sym)),
                'simplified_correct': str(sympy.simplify(correct_sym)),
            }
        except ImportError:
            return {'correct': False, 'score': 0.0, 'feedback': 'SymPy not available for expression scoring'}
        except Exception as e:
            return {'correct': False, 'score': 0.0, 'feedback': f'Error parsing expression: {e}'}

    @staticmethod
    def score_matrix(student_matrix, correct_matrix, tolerance=0.01):
        """Score matrix answers with element-wise comparison."""
        try:
            import sympy

            if isinstance(student_matrix, str):
                import json
                student_matrix = json.loads(student_matrix)
            if isinstance(correct_matrix, str):
                import json
                correct_matrix = json.loads(correct_matrix)

            s_mat = sympy.Matrix(student_matrix)
            c_mat = sympy.Matrix(correct_matrix)

            if s_mat.shape != c_mat.shape:
                return {
                    'correct': False, 'score': 0.0,
                    'feedback': f'Matrix dimensions mismatch: expected {c_mat.shape}, got {s_mat.shape}',
                }

            total_elements = s_mat.rows * s_mat.cols
            correct_elements = 0
            for i in range(s_mat.rows):
                for j in range(s_mat.cols):
                    if abs(float(s_mat[i, j]) - float(c_mat[i, j])) <= tolerance:
                        correct_elements += 1

            all_correct = correct_elements == total_elements
            partial_score = correct_elements / total_elements if total_elements > 0 else 0

            return {
                'correct': all_correct,
                'score': 1.0 if all_correct else partial_score,
                'feedback': 'Correct!' if all_correct else f'{correct_elements}/{total_elements} elements correct',
                'correct_elements': correct_elements,
                'total_elements': total_elements,
            }
        except ImportError:
            return {'correct': False, 'score': 0.0, 'feedback': 'SymPy not available for matrix scoring'}
        except Exception as e:
            return {'correct': False, 'score': 0.0, 'feedback': f'Error scoring matrix: {e}'}

    @staticmethod
    def evaluate_expression(expr_str):
        """Safely evaluate a mathematical expression."""
        try:
            import sympy
            result = sympy.sympify(expr_str, evaluate=True)
            return float(result.evalf())
        except ImportError:
            raise ValueError("SymPy not available")
        except Exception as e:
            raise ValueError(f"Cannot evaluate expression: {e}")
