use crate::{error::CapabilityError, permission::Permission, rules::fs::FS_RULES};
use syn::{Error, visit_mut::VisitMut};

pub struct CapabilityRewriter {
    pub permissions: Vec<Permission>,
    pub errors: Vec<Error>,
}

impl VisitMut for CapabilityRewriter {
    fn visit_expr_mut(&mut self, expr: &mut syn::Expr) {
        if let syn::Expr::Call(call) = expr
            && let syn::Expr::Path(path_expr) = &mut *call.func
        {
            let segments: Vec<String> = path_expr.path.segments.iter().map(|s| s.ident.to_string()).collect();

            for rule in FS_RULES {
                if segments.len() >= rule.path.len() && segments[segments.len() - rule.path.len()..].iter().map(|s| s.as_str()).eq(rule.path.iter().copied()) {
                    if !self.permissions.contains(&rule.permission) {
                        self.errors.push(
                            CapabilityError {
                                message: format!("missing capability `{}`", rule.permission),
                            }
                            .into_syn_error(&path_expr.path, rule.permission),
                        );

                        return;
                    }

                    path_expr.path = syn::parse_str(rule.replacement).unwrap();

                    break;
                }
            }
        }

        syn::visit_mut::visit_expr_mut(self, expr);
    }
}
