use rustpython_ast::{Cmpop, Expr, ExprKind};

use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::fix::Fix;
use crate::registry::Diagnostic;
use crate::violations;

/// SIM300
pub fn yoda_conditions(
    checker: &mut Checker,
    expr: &Expr,
    left: &Expr,
    ops: &[Cmpop],
    comparators: &[Expr],
) {
    if !matches!(ops[..], [Cmpop::Eq]) {
        return;
    }
    if comparators.len() != 1 {
        return;
    }
    if !matches!(left.node, ExprKind::Constant { .. }) {
        return;
    }
    let right = comparators.first().unwrap();
    if matches!(right.node, ExprKind::Constant { .. }) {
        return;
    }

    // Slice exact content to preserve formatting.
    let constant = checker
        .locator
        .slice_source_code_range(&Range::from_located(left));
    let variable = checker
        .locator
        .slice_source_code_range(&Range::from_located(right));

    let mut diagnostic = Diagnostic::new(
        violations::YodaConditions {
            constant: constant.to_string(),
            variable: variable.to_string(),
        },
        Range::from_located(expr),
    );
    if checker.patch(diagnostic.kind.code()) {
        diagnostic.amend(Fix::replacement(
            format!("{variable} == {constant}"),
            left.location,
            right.end_location.unwrap(),
        ));
    }
    checker.diagnostics.push(diagnostic);
}
