//! Enhanced borrowing context for proper ownership pattern inference
//!
//! This module provides comprehensive analysis of parameter usage patterns
//! to determine optimal borrowing strategies for function parameters.

#[cfg(feature = "decision-tracing")]
use depyler_hir::decision_trace::DecisionCategory;
use depyler_hir::hir::{AssignTarget, HirExpr, HirFunction, HirStmt, Type as PythonType};
use depyler_hir::trace_decision;
use crate::type_mapper::{RustType, TypeMapper};
use indexmap::IndexMap;
use std::collections::{HashMap, HashSet};

/// Comprehensive borrowing context for analyzing parameter usage
#[derive(Debug)]
pub struct BorrowingContext {
    /// Usage patterns for each parameter
    param_usage: HashMap<String, ParameterUsagePattern>,
    /// Variables that are moved or consumed
    moved_vars: HashSet<String>,
    /// Variables that are borrowed mutably
    mut_borrowed_vars: HashSet<String>,
    /// Variables that are borrowed immutably
    immut_borrowed_vars: HashSet<String>,
    /// Control flow context stack
    context_stack: Vec<AnalysisContext>,
    /// Function return type for escape analysis
    return_type: Option<PythonType>,
}

/// Detailed parameter usage pattern
#[derive(Debug, Clone, Default)]
pub struct ParameterUsagePattern {
    /// Parameter is read without modification
    pub is_read: bool,
    /// Parameter is modified (assigned to)
    pub is_mutated: bool,
    /// Parameter is moved/consumed (passed to function that takes ownership)
    pub is_moved: bool,
    /// Parameter escapes through return
    pub escapes_through_return: bool,
    /// Parameter is stored in a struct/container
    pub is_stored: bool,
    /// Parameter is used in a closure
    pub used_in_closure: bool,
    /// Parameter is used in loops (affects borrowing strategy)
    pub used_in_loop: bool,
    /// Nested field access patterns
    pub field_accesses: HashSet<String>,
    /// Method calls on the parameter
    pub method_calls: HashSet<String>,
    /// Specific expressions where parameter is used
    pub usage_sites: Vec<UsageSite>,
}

/// Site where a parameter is used
#[derive(Debug, Clone)]
pub struct UsageSite {
    /// Type of usage
    pub usage_type: UsageType,
    /// Whether in a loop context
    pub in_loop: bool,
    /// Whether in a conditional context
    pub in_conditional: bool,
    /// Depth of borrowing (for nested borrows)
    pub borrow_depth: usize,
}

/// Type of parameter usage
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum UsageType {
    /// Simple read access
    Read,
    /// Mutable access
    Write,
    /// Method call that might mutate
    MethodCall(String),
    /// Passed to another function
    FunctionArg { takes_ownership: bool },
    /// Returned from function
    Return,
    /// Stored in a data structure
    Store,
    /// Used in a closure
    Closure { captures_by_value: bool },
    /// Field access
    FieldAccess(String),
    /// Index access
    IndexAccess,
}

/// Analysis context for control flow
#[derive(Debug, Clone)]
#[allow(dead_code)]
enum AnalysisContext {
    Loop,
    Conditional,
    Closure { captures: HashSet<String> },
    Function,
}

/// Result of borrowing analysis
#[derive(Debug, Clone)]
pub struct BorrowingAnalysisResult {
    /// Recommended borrowing strategy for each parameter
    pub param_strategies: IndexMap<String, BorrowingStrategy>,
    /// Additional insights
    pub insights: Vec<BorrowingInsight>,
}

/// Recommended borrowing strategy
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum BorrowingStrategy {
    /// Take ownership (move)
    TakeOwnership,
    /// Borrow immutably
    BorrowImmutable { lifetime: Option<String> },
    /// Borrow mutably
    BorrowMutable { lifetime: Option<String> },
    /// Use Cow for flexibility
    UseCow { lifetime: String },
    /// Use Arc/Rc for shared ownership
    UseSharedOwnership { is_thread_safe: bool },
}

/// Insights from borrowing analysis
#[derive(Debug, Clone)]
pub enum BorrowingInsight {
    /// Parameter could be borrowed but is currently moved
    UnnecessaryMove(String),
    /// Parameter could use a more specific lifetime
    LifetimeOptimization { param: String, suggestion: String },
    /// Parameter access pattern suggests Copy trait
    SuggestCopyDerive(String),
    /// Multiple mutable borrows detected
    PotentialBorrowConflict {
        param: String,
        locations: Vec<String>,
    },
}

impl BorrowingContext {
    pub fn new(return_type: Option<PythonType>) -> Self {
        Self {
            param_usage: HashMap::new(),
            moved_vars: HashSet::new(),
            mut_borrowed_vars: HashSet::new(),
            immut_borrowed_vars: HashSet::new(),
            context_stack: vec![AnalysisContext::Function],
            return_type,
        }
    }

    /// Analyze a function to determine optimal borrowing strategies
    pub fn analyze_function(
        &mut self,
        func: &HirFunction,
        type_mapper: &TypeMapper,
    ) -> BorrowingAnalysisResult {
        // Initialize parameter tracking
        for param in &func.params {
            self.param_usage
                .insert(param.name.clone(), ParameterUsagePattern::default());
        }

        // Analyze function body
        for stmt in &func.body {
            self.analyze_statement(stmt);
        }

        // Determine borrowing strategies based on usage patterns
        self.determine_strategies(func, type_mapper)
    }

    /// Analyze a statement for parameter usage
    fn analyze_statement(&mut self, stmt: &HirStmt) {
        match stmt {
            HirStmt::Assign { target, value, .. } => {
                // Check if assigning to a parameter (mutation)
                // DEPYLER-1217: Handle all assignment targets that mutate parameters
                let in_loop = self.is_in_loop();
                let in_conditional = self.is_in_conditional();
                self.check_target_mutation(target, in_loop, in_conditional);
                self.analyze_expression(value, 0);
            }
            HirStmt::Return(expr) => {
                if let Some(e) = expr {
                    self.analyze_expression_for_return(e);
                }
            }
            HirStmt::If {
                condition,
                then_body,
                else_body,
            } => {
                self.analyze_expression(condition, 0);
                self.context_stack.push(AnalysisContext::Conditional);
                for stmt in then_body {
                    self.analyze_statement(stmt);
                }
                if let Some(else_stmts) = else_body {
                    for stmt in else_stmts {
                        self.analyze_statement(stmt);
                    }
                }
                self.context_stack.pop();
            }
            HirStmt::While { condition, body } => {
                self.context_stack.push(AnalysisContext::Loop);
                self.analyze_expression(condition, 0);
                for stmt in body {
                    self.analyze_statement(stmt);
                }
                self.context_stack.pop();
            }
            HirStmt::For {
                target: _,
                iter,
                body,
            } => {
                self.context_stack.push(AnalysisContext::Loop);
                self.analyze_expression(iter, 0);
                for stmt in body {
                    self.analyze_statement(stmt);
                }
                self.context_stack.pop();
            }
            HirStmt::Expr(expr) => {
                self.analyze_expression(expr, 0);
            }
            HirStmt::Raise { exception, cause } => {
                if let Some(exc) = exception {
                    self.analyze_expression(exc, 0);
                }
                if let Some(c) = cause {
                    self.analyze_expression(c, 0);
                }
            }
            HirStmt::Break { .. } | HirStmt::Continue { .. } | HirStmt::Pass => {
                // Break, continue, and pass don't analyze any expressions
            }
            // DEPYLER-0614: Recursively analyze Block statements
            HirStmt::Block(stmts) => {
                for s in stmts {
                    self.analyze_statement(s);
                }
            }
            HirStmt::Assert { test, msg } => {
                // Analyze the test expression and optional message
                self.analyze_expression(test, 0);
                if let Some(message) = msg {
                    self.analyze_expression(message, 0);
                }
            }
            HirStmt::With {
                context,
                target: _,
                body,
                ..
            } => {
                // Analyze context expression
                self.analyze_expression(context, 0);

                // Track the target variable if present
                // Note: We don't track local variables here, only parameters

                // Analyze body statements
                for stmt in body {
                    self.analyze_statement(stmt);
                }
            }
            HirStmt::Try {
                body,
                handlers,
                orelse,
                finalbody,
            } => {
                // Analyze try body
                for stmt in body {
                    self.analyze_statement(stmt);
                }

                // Analyze except handlers
                for handler in handlers {
                    for stmt in &handler.body {
                        self.analyze_statement(stmt);
                    }
                }

                // Analyze else clause
                if let Some(else_stmts) = orelse {
                    for stmt in else_stmts {
                        self.analyze_statement(stmt);
                    }
                }

                // Analyze finally clause
                if let Some(finally_stmts) = finalbody {
                    for stmt in finally_stmts {
                        self.analyze_statement(stmt);
                    }
                }
            }
            // DEPYLER-0427: Nested function support
            // Analyze nested function body for parameter usage
            HirStmt::FunctionDef { body, .. } => {
                for stmt in body {
                    self.analyze_statement(stmt);
                }
            }
        }
    }

    /// DEPYLER-1217: Helper to check if an assignment target mutates a parameter
    /// Recursively handles index, attribute, and tuple targets
    fn check_target_mutation(
        &mut self,
        target: &AssignTarget,
        in_loop: bool,
        in_conditional: bool,
    ) {
        match target {
            AssignTarget::Symbol(symbol) => {
                if let Some(usage) = self.param_usage.get_mut(symbol) {
                    usage.is_mutated = true;
                    usage.usage_sites.push(UsageSite {
                        usage_type: UsageType::Write,
                        in_loop,
                        in_conditional,
                        borrow_depth: 0,
                    });
                }
            }
            // DEPYLER-1217: Index assignment (arr[i] = value) mutates the base
            AssignTarget::Index { base, .. } => {
                if let HirExpr::Var(var_name) = base.as_ref() {
                    if let Some(usage) = self.param_usage.get_mut(var_name) {
                        usage.is_mutated = true;
                        usage.usage_sites.push(UsageSite {
                            usage_type: UsageType::Write,
                            in_loop,
                            in_conditional,
                            borrow_depth: 0,
                        });
                    }
                }
            }
            // DEPYLER-1217: Attribute assignment (obj.field = value) mutates the base
            AssignTarget::Attribute { value, .. } => {
                if let HirExpr::Var(var_name) = value.as_ref() {
                    if let Some(usage) = self.param_usage.get_mut(var_name) {
                        usage.is_mutated = true;
                        usage.usage_sites.push(UsageSite {
                            usage_type: UsageType::Write,
                            in_loop,
                            in_conditional,
                            borrow_depth: 0,
                        });
                    }
                }
            }
            // DEPYLER-1217: Tuple unpacking can contain index targets
            // e.g., arr[i], arr[j] = arr[j], arr[i] (swap pattern)
            AssignTarget::Tuple(targets) => {
                for t in targets {
                    self.check_target_mutation(t, in_loop, in_conditional);
                }
            }
        }
    }

    /// Analyze an expression for parameter usage
    fn analyze_expression(&mut self, expr: &HirExpr, borrow_depth: usize) {
        match expr {
            HirExpr::Var(name) => {
                let in_loop = self.is_in_loop();
                let in_conditional = self.is_in_conditional();
                if let Some(usage) = self.param_usage.get_mut(name) {
                    usage.is_read = true;
                    usage.usage_sites.push(UsageSite {
                        usage_type: UsageType::Read,
                        in_loop,
                        in_conditional,
                        borrow_depth,
                    });
                    if in_loop {
                        usage.used_in_loop = true;
                    }
                }
            }
            HirExpr::Attribute { value, attr } => {
                if let HirExpr::Var(name) = &**value {
                    let in_loop = self.is_in_loop();
                    let in_conditional = self.is_in_conditional();
                    if let Some(usage) = self.param_usage.get_mut(name) {
                        usage.field_accesses.insert(attr.clone());
                        usage.usage_sites.push(UsageSite {
                            usage_type: UsageType::FieldAccess(attr.clone()),
                            in_loop,
                            in_conditional,
                            borrow_depth: borrow_depth + 1,
                        });
                    }
                }
                self.analyze_expression(value, borrow_depth + 1);
            }
            HirExpr::Call { func, args, .. } => {
                // Analyze function calls to determine if parameters are moved
                let in_loop = self.is_in_loop();
                let in_conditional = self.is_in_conditional();
                for (i, arg) in args.iter().enumerate() {
                    if let HirExpr::Var(name) = arg {
                        let takes_ownership = self.function_takes_ownership(func, i);
                        if let Some(usage) = self.param_usage.get_mut(name) {
                            // Conservative: assume ownership transfer unless we know better
                            if takes_ownership {
                                usage.is_moved = true;
                                self.moved_vars.insert(name.clone());
                            }
                            usage.usage_sites.push(UsageSite {
                                usage_type: UsageType::FunctionArg { takes_ownership },
                                in_loop,
                                in_conditional,
                                borrow_depth,
                            });
                        }
                    }
                    self.analyze_expression(arg, borrow_depth);
                }
            }
            HirExpr::Index { base, index } => {
                if let HirExpr::Var(name) = &**base {
                    let in_loop = self.is_in_loop();
                    let in_conditional = self.is_in_conditional();
                    if let Some(usage) = self.param_usage.get_mut(name) {
                        usage.usage_sites.push(UsageSite {
                            usage_type: UsageType::IndexAccess,
                            in_loop,
                            in_conditional,
                            borrow_depth: borrow_depth + 1,
                        });
                    }
                }
                self.analyze_expression(base, borrow_depth + 1);
                self.analyze_expression(index, borrow_depth);
            }
            HirExpr::Binary { left, right, .. } => {
                self.analyze_expression(left, borrow_depth);
                self.analyze_expression(right, borrow_depth);
            }
            HirExpr::Unary { operand, .. } => {
                self.analyze_expression(operand, borrow_depth);
            }
            HirExpr::List(elements) | HirExpr::Tuple(elements) => {
                for elem in elements {
                    self.analyze_expression(elem, borrow_depth);
                }
            }
            HirExpr::Dict(pairs) => {
                for (k, v) in pairs {
                    self.analyze_expression(k, borrow_depth);
                    self.analyze_expression(v, borrow_depth);
                }
            }
            HirExpr::Borrow { expr, mutable } => {
                if let HirExpr::Var(name) = &**expr {
                    if *mutable {
                        self.mut_borrowed_vars.insert(name.clone());
                    } else {
                        self.immut_borrowed_vars.insert(name.clone());
                    }
                }
                self.analyze_expression(expr, borrow_depth + 1);
            }
            HirExpr::MethodCall { object, args, .. } => {
                self.analyze_expression(object, borrow_depth);
                for arg in args {
                    self.analyze_expression(arg, borrow_depth);
                }
            }
            HirExpr::Slice {
                base,
                start,
                stop,
                step,
            } => {
                self.analyze_expression(base, borrow_depth);
                if let Some(s) = start {
                    self.analyze_expression(s, borrow_depth);
                }
                if let Some(s) = stop {
                    self.analyze_expression(s, borrow_depth);
                }
                if let Some(s) = step {
                    self.analyze_expression(s, borrow_depth);
                }
            }
            HirExpr::Literal(_) => {}
            HirExpr::ListComp {
                element,
                generators,
            } => {
                // List comprehensions create a new scope
                self.context_stack.push(AnalysisContext::Loop);

                // Analyze all generators
                for gen in generators {
                    // Analyze the iterator
                    self.analyze_expression(&gen.iter, borrow_depth);

                    // Analyze all conditions
                    for cond in &gen.conditions {
                        self.analyze_expression(cond, borrow_depth);
                    }
                }

                // Analyze the element expression
                self.analyze_expression(element, borrow_depth);

                self.context_stack.pop();
            }
            HirExpr::FString { .. } => {
                // FString support not yet implemented for borrowing analysis
            }
            HirExpr::Lambda { params: _, body } => {
                // Lambda functions capture variables by reference
                // For now, treat lambda bodies like any other expression
                self.analyze_expression(body, borrow_depth);
            }
            HirExpr::Set(elements) | HirExpr::FrozenSet(elements) => {
                for elem in elements {
                    self.analyze_expression(elem, borrow_depth);
                }
            }
            HirExpr::SetComp {
                element,
                generators,
            } => {
                // Set comprehensions create a new scope
                self.context_stack.push(AnalysisContext::Loop);

                // Analyze all generators
                for gen in generators {
                    // Analyze the iterator
                    self.analyze_expression(&gen.iter, borrow_depth);

                    // Analyze all conditions
                    for cond in &gen.conditions {
                        self.analyze_expression(cond, borrow_depth);
                    }
                }

                // Analyze the element expression
                self.analyze_expression(element, borrow_depth);

                self.context_stack.pop();
            }
            HirExpr::DictComp {
                key,
                value,
                generators,
            } => {
                // Dict comprehensions create a new scope
                self.context_stack.push(AnalysisContext::Loop);

                // Analyze all generators
                for gen in generators {
                    // Analyze the iterator
                    self.analyze_expression(&gen.iter, borrow_depth);

                    // Analyze all conditions
                    for cond in &gen.conditions {
                        self.analyze_expression(cond, borrow_depth);
                    }
                }

                // Analyze the key and value expressions
                self.analyze_expression(key, borrow_depth);
                self.analyze_expression(value, borrow_depth);

                self.context_stack.pop();
            }
            HirExpr::Await { value } => {
                // Await expressions don't change parameter usage patterns
                self.analyze_expression(value, borrow_depth);
            }
            HirExpr::Yield { value } => {
                // Yield expressions pass values to the iterator
                if let Some(v) = value {
                    self.analyze_expression(v, borrow_depth);
                }
            }
            HirExpr::IfExpr { test, body, orelse } => {
                // Analyze all three parts of the ternary expression
                self.analyze_expression(test, borrow_depth);
                self.analyze_expression(body, borrow_depth);
                self.analyze_expression(orelse, borrow_depth);
            }
            HirExpr::SortByKey {
                iterable, key_body, ..
            } => {
                // Analyze the iterable and the key lambda body
                self.analyze_expression(iterable, borrow_depth);
                self.analyze_expression(key_body, borrow_depth);
            }
            HirExpr::GeneratorExp {
                element,
                generators,
            } => {
                // Analyze element expression and all generator iterables
                self.analyze_expression(element, borrow_depth);
                for gen in generators {
                    self.analyze_expression(&gen.iter, borrow_depth);
                    for cond in &gen.conditions {
                        self.analyze_expression(cond, borrow_depth);
                    }
                }
            }
            // DEPYLER-0188: Walrus operator - analyze the value expression
            HirExpr::NamedExpr { value, .. } => {
                self.analyze_expression(value, borrow_depth);
            }
            // DEPYLER-0188: Dynamic call - analyze callee and arguments
            HirExpr::DynamicCall { callee, args, .. } => {
                self.analyze_expression(callee, borrow_depth);
                for arg in args {
                    self.analyze_expression(arg, borrow_depth);
                }
            }
        }
    }

    /// Analyze expression in return context
    /// DEPYLER-0303: Only mark parameters as escaping if they are DIRECTLY returned,
    /// not when used in operations that produce different types (e.g., `key in dict` → bool)
    fn analyze_expression_for_return(&mut self, expr: &HirExpr) {
        match expr {
            HirExpr::Var(name) => {
                // Parameter is directly returned - it escapes
                if let Some(usage) = self.param_usage.get_mut(name) {
                    usage.escapes_through_return = true;
                    usage.usage_sites.push(UsageSite {
                        usage_type: UsageType::Return,
                        in_loop: false,
                        in_conditional: false,
                        borrow_depth: 0,
                    });
                }
            }
            HirExpr::Binary { left, right, .. } => {
                // Binary operations (comparisons, arithmetic, etc.) produce NEW values
                // Parameters are used but don't escape - just analyze normally
                self.analyze_expression(left, 0);
                self.analyze_expression(right, 0);
            }
            _ => self.analyze_expression(expr, 0),
        }
    }

    /// Determine if a function takes ownership of its argument
    fn function_takes_ownership(&self, func_name: &str, _arg_index: usize) -> bool {
        // Known functions that borrow
        let borrowing_functions = [
            "len",
            "str",
            "repr",
            "format",
            "print",
            "isinstance",
            "hasattr",
            "getattr",
            "contains",
            "startswith",
            "endswith",
            "find",
            "index",
            "count",
            // DEPYLER-0436: Type conversion functions borrow their arguments
            "int",
            "float",
            "bool",
            // DEPYLER-0732: Aggregate functions that iterate without taking ownership
            // In Rust, these use .iter() which borrows the collection
            "sum",
            "min",
            "max",
            "any",
            "all",
            "sorted",
            "reversed",
            "enumerate",
            "zip",
            "map",
            "filter",
        ];

        // Known functions that take ownership
        let ownership_functions = ["append", "extend", "insert", "remove", "pop", "sort"];

        if borrowing_functions.contains(&func_name) {
            false
        } else if ownership_functions.contains(&func_name) {
            true
        } else {
            // DEPYLER-0732: Python semantics - function calls pass references, not ownership
            // In Python, passing a value to a function doesn't transfer ownership.
            // The caller can still use the value after the call.
            // Default to borrowing to match Python semantics and prevent E0382 errors.
            false
        }
    }

    /// Check if currently in a loop context
    fn is_in_loop(&self) -> bool {
        self.context_stack
            .iter()
            .any(|ctx| matches!(ctx, AnalysisContext::Loop))
    }

    /// Check if currently in a conditional context
    fn is_in_conditional(&self) -> bool {
        self.context_stack
            .iter()
            .any(|ctx| matches!(ctx, AnalysisContext::Conditional))
    }

    /// Determine optimal borrowing strategies based on usage patterns
    fn determine_strategies(
        &self,
        func: &HirFunction,
        type_mapper: &TypeMapper,
    ) -> BorrowingAnalysisResult {
        let mut strategies = IndexMap::new();
        let mut insights = Vec::new();

        for param in &func.params {
            let usage = self
                .param_usage
                .get(&param.name)
                .cloned()
                .unwrap_or_default();
            let rust_type = type_mapper.map_type(&param.ty);

            let strategy = self.determine_parameter_strategy(
                &param.name,
                &usage,
                &rust_type,
                &param.ty,
                &mut insights,
            );

            strategies.insert(param.name.clone(), strategy);
        }

        BorrowingAnalysisResult {
            param_strategies: strategies,
            insights,
        }
    }

    /// Determine strategy for a single parameter
    fn determine_parameter_strategy(
        &self,
        param_name: &str,
        usage: &ParameterUsagePattern,
        rust_type: &RustType,
        python_type: &PythonType,
        insights: &mut Vec<BorrowingInsight>,
    ) -> BorrowingStrategy {
        // CITL: Trace borrow strategy determination
        trace_decision!(
            category = DecisionCategory::BorrowStrategy,
            name = "param_strategy",
            chosen = param_name,
            alternatives = ["owned", "borrowed", "mutable_ref", "copy", "arc"],
            confidence = 0.85
        );

        // Always check if type is Copy for insights
        if self.is_copy_type(rust_type) {
            insights.push(BorrowingInsight::SuggestCopyDerive(param_name.to_string()));
        }

        // If parameter is moved, we must take ownership
        if usage.is_moved {
            // Check if move is necessary
            if !usage.escapes_through_return && !usage.is_stored {
                insights.push(BorrowingInsight::UnnecessaryMove(param_name.to_string()));
            }
            return BorrowingStrategy::TakeOwnership;
        }

        // If parameter escapes through return and matches return type, take ownership
        // (except for strings which have special handling)
        if usage.escapes_through_return && !matches!(python_type, PythonType::String) {
            if let Some(ref ret_type) = self.return_type {
                if python_type == ret_type {
                    return BorrowingStrategy::TakeOwnership;
                }
            }
        }

        // If parameter is stored in a structure, consider shared ownership
        if usage.is_stored {
            return BorrowingStrategy::UseSharedOwnership {
                is_thread_safe: false,
            };
        }

        // If used in closure, determine capture strategy
        if usage.used_in_closure {
            // Complex analysis needed - for now, be conservative
            return BorrowingStrategy::TakeOwnership;
        }

        // Check if type is Copy - take ownership (cheap)
        if self.is_copy_type(rust_type) {
            return BorrowingStrategy::TakeOwnership; // Cheap to copy
        }

        // String-specific optimizations
        if matches!(python_type, PythonType::String) {
            return self.determine_string_strategy(param_name, usage);
        }

        // Determine mutability needs
        if usage.is_mutated {
            BorrowingStrategy::BorrowMutable { lifetime: None }
        } else if usage.is_read {
            BorrowingStrategy::BorrowImmutable { lifetime: None }
        } else {
            // Parameter unused - take ownership (simplest)
            BorrowingStrategy::TakeOwnership
        }
    }

    /// Determine optimal string handling strategy
    fn determine_string_strategy(
        &self,
        _param_name: &str,
        usage: &ParameterUsagePattern,
    ) -> BorrowingStrategy {
        // CITL: Trace string strategy determination
        trace_decision!(
            category = DecisionCategory::BorrowStrategy,
            name = "string_strategy",
            chosen = "string_analysis",
            alternatives = ["String", "&str", "Cow", "AsRef", "Into"],
            confidence = 0.82
        );

        // For strings that are reassigned (not string mutation itself),
        // we can actually take ownership since we're replacing the entire string
        // This is a Python-specific pattern where `s = s + "!"` creates a new string

        // If string is moved to another function, we need ownership
        if usage.is_moved {
            return BorrowingStrategy::TakeOwnership;
        }

        // If string is reassigned (Python pattern), take ownership
        // This must come before escape check to handle mutation correctly
        if usage.is_mutated {
            return BorrowingStrategy::TakeOwnership;
        }

        // If string escapes, we need to take ownership to avoid lifetime issues
        // DEPYLER-0357: Cow lifetime mismatch resolution
        // Previous behavior: Generated Cow<'static, str> which creates impossible
        // lifetime constraints when returning borrowed parameters
        // New behavior: Use owned String for simplicity and correctness
        if usage.escapes_through_return {
            return BorrowingStrategy::TakeOwnership;
        }

        // For read-only strings, prefer borrowing
        if usage.is_read && !usage.is_moved && !usage.is_mutated {
            return BorrowingStrategy::BorrowImmutable { lifetime: None };
        }

        // Default to ownership for simplicity
        BorrowingStrategy::TakeOwnership
    }

    /// Check if a type implements Copy
    #[allow(clippy::only_used_in_recursion)]
    fn is_copy_type(&self, rust_type: &RustType) -> bool {
        match rust_type {
            RustType::Primitive(_) => true,
            RustType::Unit => true,
            RustType::Tuple(types) => types.iter().all(|t| self.is_copy_type(t)),
            _ => false,
        }
    }

    /// DEPYLER-PHASE2: Run enhanced ownership analysis with escape analysis
    ///
    /// This method combines the traditional borrowing analysis with the new
    /// escape analysis to detect use-after-move violations and aliasing patterns.
    ///
    /// Returns enhanced insights including:
    /// - Use-after-move errors with suggested fixes
    /// - Aliasing patterns requiring cloning
    /// - Sites where borrows should be used instead of moves
    pub fn analyze_with_escape_analysis(
        &mut self,
        func: &depyler_hir::hir::HirFunction,
        type_mapper: &TypeMapper,
    ) -> EnhancedBorrowingResult {
        use crate::escape_analysis::{analyze_ownership, OwnershipFix};

        // Run traditional borrowing analysis
        let basic_result = self.analyze_function(func, type_mapper);

        // Run escape analysis
        let ownership_result = analyze_ownership(func);

        // Combine results
        let mut ownership_fixes = Vec::new();

        for error in &ownership_result.use_after_move_errors {
            ownership_fixes.push(OwnershipFixSite {
                variable: error.var.clone(),
                site_index: error.move_site.stmt_index,
                fix: match &error.fix {
                    OwnershipFix::Borrow => OwnershipFixType::UseBorrow,
                    OwnershipFix::MutableBorrow => OwnershipFixType::UseMutableBorrow,
                    OwnershipFix::Clone => OwnershipFixType::InsertClone,
                    OwnershipFix::CloneAtAssignment { var } => {
                        OwnershipFixType::CloneAtAssignment(var.clone())
                    }
                    OwnershipFix::Reject { reason } => {
                        OwnershipFixType::RejectPattern(reason.clone())
                    }
                },
            });
        }

        for pattern in &ownership_result.aliasing_patterns {
            if pattern.source_used_after && pattern.alias_used_after {
                ownership_fixes.push(OwnershipFixSite {
                    variable: pattern.alias.clone(),
                    site_index: 0, // Will be filled with actual assignment index
                    fix: OwnershipFixType::CloneAtAssignment(pattern.source.clone()),
                });
            }
        }

        EnhancedBorrowingResult {
            basic_result,
            use_after_move_count: ownership_result.use_after_move_errors.len(),
            aliasing_pattern_count: ownership_result.aliasing_patterns.len(),
            ownership_fixes,
        }
    }
}

/// Result of enhanced borrowing analysis with escape analysis
#[derive(Debug, Clone)]
pub struct EnhancedBorrowingResult {
    /// Traditional borrowing analysis result
    pub basic_result: BorrowingAnalysisResult,
    /// Number of use-after-move errors detected
    pub use_after_move_count: usize,
    /// Number of aliasing patterns requiring cloning
    pub aliasing_pattern_count: usize,
    /// Suggested ownership fixes
    pub ownership_fixes: Vec<OwnershipFixSite>,
}

/// A site where an ownership fix is needed
#[derive(Debug, Clone)]
pub struct OwnershipFixSite {
    /// Variable name
    pub variable: String,
    /// Statement index where fix is needed
    pub site_index: usize,
    /// Type of fix to apply
    pub fix: OwnershipFixType,
}

/// Type of ownership fix to apply
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum OwnershipFixType {
    /// Change `f(x)` to `f(&x)`
    UseBorrow,
    /// Change `f(x)` to `f(&mut x)`
    UseMutableBorrow,
    /// Change `f(x)` to `f(x.clone())`
    InsertClone,
    /// Change `let b = a` to `let b = a.clone()`
    CloneAtAssignment(String),
    /// Pattern cannot be fixed - requires Poka-Yoke rejection
    RejectPattern(String),
}

#[cfg(test)]
mod tests {
    use super::*;
    use depyler_hir::hir::{FunctionProperties, HirParam, Literal};
    use depyler_annotations::TranspilationAnnotations;
    use smallvec::smallvec;

    #[test]
    fn test_basic_borrowing_analysis() {
        let mut ctx = BorrowingContext::new(Some(PythonType::Int));
        let type_mapper = TypeMapper::new();

        let func = HirFunction {
            name: "add_one".to_string(),
            params: smallvec![HirParam::new("x".to_string(), PythonType::Int)],
            ret_type: PythonType::Int,
            body: vec![HirStmt::Return(Some(HirExpr::Binary {
                op: depyler_hir::hir::BinOp::Add,
                left: Box::new(HirExpr::Var("x".to_string())),
                right: Box::new(HirExpr::Literal(Literal::Int(1))),
            }))],
            properties: FunctionProperties::default(),
            annotations: TranspilationAnnotations::default(),
            docstring: None,
        };

        let result = ctx.analyze_function(&func, &type_mapper);

        // Integer parameter should be taken by value (Copy type)
        let x_strategy = result.param_strategies.get("x").unwrap();
        assert_eq!(*x_strategy, BorrowingStrategy::TakeOwnership);
    }

    #[test]
    fn test_string_borrowing() {
        let mut ctx = BorrowingContext::new(Some(PythonType::Int));
        let type_mapper = TypeMapper::new();

        let func = HirFunction {
            name: "string_len".to_string(),
            params: smallvec![HirParam::new("s".to_string(), PythonType::String)],
            ret_type: PythonType::Int,
            body: vec![HirStmt::Return(Some(HirExpr::Call {
                func: "len".to_string(),
                args: vec![HirExpr::Var("s".to_string())],
                kwargs: vec![],
            }))],
            properties: FunctionProperties::default(),
            annotations: TranspilationAnnotations::default(),
            docstring: None,
        };

        let result = ctx.analyze_function(&func, &type_mapper);

        // String parameter should be borrowed (not moved)
        let s_strategy = result.param_strategies.get("s").unwrap();
        assert!(matches!(
            s_strategy,
            BorrowingStrategy::BorrowImmutable { .. }
        ));
    }

    #[test]
    fn test_mutation_detection() {
        let mut ctx = BorrowingContext::new(None);
        let type_mapper = TypeMapper::new();

        let func = HirFunction {
            name: "mutate_list".to_string(),
            params: smallvec![HirParam::new(
                "lst".to_string(),
                PythonType::List(Box::new(PythonType::Int))
            )],
            ret_type: PythonType::None,
            body: vec![HirStmt::Expr(HirExpr::Call {
                func: "append".to_string(),
                args: vec![
                    HirExpr::Var("lst".to_string()),
                    HirExpr::Literal(Literal::Int(42)),
                ],
                kwargs: vec![],
            })],
            properties: FunctionProperties::default(),
            annotations: TranspilationAnnotations::default(),
            docstring: None,
        };

        let result = ctx.analyze_function(&func, &type_mapper);

        // List parameter should be moved (append takes ownership in our analysis)
        let lst_strategy = result.param_strategies.get("lst").unwrap();
        assert_eq!(*lst_strategy, BorrowingStrategy::TakeOwnership);
    }

    // BorrowingContext tests
    #[test]
    fn test_borrowing_context_new_with_none() {
        let ctx = BorrowingContext::new(None);
        assert!(ctx.param_usage.is_empty());
        assert!(ctx.moved_vars.is_empty());
        assert!(ctx.mut_borrowed_vars.is_empty());
        assert!(ctx.immut_borrowed_vars.is_empty());
    }

    #[test]
    fn test_borrowing_context_new_with_return_type() {
        let ctx = BorrowingContext::new(Some(PythonType::String));
        assert!(ctx.return_type.is_some());
    }

    // ParameterUsagePattern tests
    #[test]
    fn test_parameter_usage_pattern_default() {
        let pattern = ParameterUsagePattern::default();
        assert!(!pattern.is_read);
        assert!(!pattern.is_mutated);
        assert!(!pattern.is_moved);
        assert!(!pattern.escapes_through_return);
        assert!(!pattern.is_stored);
        assert!(!pattern.used_in_closure);
        assert!(!pattern.used_in_loop);
        assert!(pattern.field_accesses.is_empty());
        assert!(pattern.method_calls.is_empty());
        assert!(pattern.usage_sites.is_empty());
    }

    #[test]
    fn test_parameter_usage_pattern_clone() {
        let pattern = ParameterUsagePattern {
            is_read: true,
            is_mutated: true,
            ..Default::default()
        };
        let cloned = pattern.clone();
        assert_eq!(pattern.is_read, cloned.is_read);
        assert_eq!(pattern.is_mutated, cloned.is_mutated);
    }

    // UsageSite tests
    #[test]
    fn test_usage_site_creation() {
        let site = UsageSite {
            usage_type: UsageType::Read,
            in_loop: true,
            in_conditional: false,
            borrow_depth: 1,
        };
        assert!(site.in_loop);
        assert!(!site.in_conditional);
        assert_eq!(site.borrow_depth, 1);
    }

    #[test]
    fn test_usage_site_clone() {
        let site = UsageSite {
            usage_type: UsageType::Write,
            in_loop: false,
            in_conditional: true,
            borrow_depth: 2,
        };
        let cloned = site.clone();
        assert_eq!(site.in_loop, cloned.in_loop);
        assert_eq!(site.borrow_depth, cloned.borrow_depth);
    }

    // UsageType tests
    #[test]
    fn test_usage_type_read() {
        let usage = UsageType::Read;
        assert_eq!(usage, UsageType::Read);
    }

    #[test]
    fn test_usage_type_write() {
        let usage = UsageType::Write;
        assert_eq!(usage, UsageType::Write);
    }

    #[test]
    fn test_usage_type_method_call() {
        let usage = UsageType::MethodCall("append".to_string());
        assert!(matches!(usage, UsageType::MethodCall(_)));
    }

    #[test]
    fn test_usage_type_function_arg_owned() {
        let usage = UsageType::FunctionArg {
            takes_ownership: true,
        };
        assert!(matches!(
            usage,
            UsageType::FunctionArg {
                takes_ownership: true
            }
        ));
    }

    #[test]
    fn test_usage_type_function_arg_borrowed() {
        let usage = UsageType::FunctionArg {
            takes_ownership: false,
        };
        assert!(matches!(
            usage,
            UsageType::FunctionArg {
                takes_ownership: false
            }
        ));
    }

    #[test]
    fn test_usage_type_return() {
        let usage = UsageType::Return;
        assert_eq!(usage, UsageType::Return);
    }

    #[test]
    fn test_usage_type_store() {
        let usage = UsageType::Store;
        assert_eq!(usage, UsageType::Store);
    }

    #[test]
    fn test_usage_type_closure() {
        let usage = UsageType::Closure {
            captures_by_value: true,
        };
        assert!(matches!(
            usage,
            UsageType::Closure {
                captures_by_value: true
            }
        ));
    }

    #[test]
    fn test_usage_type_field_access() {
        let usage = UsageType::FieldAccess("name".to_string());
        assert!(matches!(usage, UsageType::FieldAccess(_)));
    }

    #[test]
    fn test_usage_type_index_access() {
        let usage = UsageType::IndexAccess;
        assert_eq!(usage, UsageType::IndexAccess);
    }

    #[test]
    fn test_usage_type_clone() {
        let usage = UsageType::MethodCall("push".to_string());
        let cloned = usage.clone();
        assert_eq!(usage, cloned);
    }

    // BorrowingStrategy tests
    #[test]
    fn test_borrowing_strategy_take_ownership() {
        let strategy = BorrowingStrategy::TakeOwnership;
        assert_eq!(strategy, BorrowingStrategy::TakeOwnership);
    }

    #[test]
    fn test_borrowing_strategy_borrow_immutable() {
        let strategy = BorrowingStrategy::BorrowImmutable { lifetime: None };
        assert!(matches!(
            strategy,
            BorrowingStrategy::BorrowImmutable { .. }
        ));
    }

    #[test]
    fn test_borrowing_strategy_borrow_immutable_with_lifetime() {
        let strategy = BorrowingStrategy::BorrowImmutable {
            lifetime: Some("'a".to_string()),
        };
        if let BorrowingStrategy::BorrowImmutable { lifetime } = &strategy {
            assert_eq!(lifetime, &Some("'a".to_string()));
        }
    }

    #[test]
    fn test_borrowing_strategy_borrow_mutable() {
        let strategy = BorrowingStrategy::BorrowMutable { lifetime: None };
        assert!(matches!(strategy, BorrowingStrategy::BorrowMutable { .. }));
    }

    #[test]
    fn test_borrowing_strategy_use_cow() {
        let strategy = BorrowingStrategy::UseCow {
            lifetime: "'a".to_string(),
        };
        if let BorrowingStrategy::UseCow { lifetime } = &strategy {
            assert_eq!(lifetime, "'a");
        }
    }

    #[test]
    fn test_borrowing_strategy_use_shared_ownership_arc() {
        let strategy = BorrowingStrategy::UseSharedOwnership {
            is_thread_safe: true,
        };
        if let BorrowingStrategy::UseSharedOwnership { is_thread_safe } = strategy {
            assert!(is_thread_safe);
        }
    }

    #[test]
    fn test_borrowing_strategy_use_shared_ownership_rc() {
        let strategy = BorrowingStrategy::UseSharedOwnership {
            is_thread_safe: false,
        };
        if let BorrowingStrategy::UseSharedOwnership { is_thread_safe } = strategy {
            assert!(!is_thread_safe);
        }
    }

    #[test]
    fn test_borrowing_strategy_clone() {
        let strategy = BorrowingStrategy::TakeOwnership;
        let cloned = strategy.clone();
        assert_eq!(strategy, cloned);
    }

    // BorrowingInsight tests
    #[test]
    fn test_borrowing_insight_unnecessary_move() {
        let insight = BorrowingInsight::UnnecessaryMove("x".to_string());
        assert!(matches!(insight, BorrowingInsight::UnnecessaryMove(_)));
    }

    #[test]
    fn test_borrowing_insight_lifetime_optimization() {
        let insight = BorrowingInsight::LifetimeOptimization {
            param: "s".to_string(),
            suggestion: "Use 'a".to_string(),
        };
        assert!(matches!(
            insight,
            BorrowingInsight::LifetimeOptimization { .. }
        ));
    }

    #[test]
    fn test_borrowing_insight_suggest_copy() {
        let insight = BorrowingInsight::SuggestCopyDerive("Point".to_string());
        assert!(matches!(insight, BorrowingInsight::SuggestCopyDerive(_)));
    }

    #[test]
    fn test_borrowing_insight_borrow_conflict() {
        let insight = BorrowingInsight::PotentialBorrowConflict {
            param: "data".to_string(),
            locations: vec!["line 10".to_string(), "line 20".to_string()],
        };
        assert!(matches!(
            insight,
            BorrowingInsight::PotentialBorrowConflict { .. }
        ));
    }

    #[test]
    fn test_borrowing_insight_clone() {
        let insight = BorrowingInsight::UnnecessaryMove("y".to_string());
        let cloned = insight.clone();
        assert!(matches!(cloned, BorrowingInsight::UnnecessaryMove(_)));
    }

    // BorrowingAnalysisResult tests
    #[test]
    fn test_borrowing_analysis_result_creation() {
        let result = BorrowingAnalysisResult {
            param_strategies: IndexMap::new(),
            insights: Vec::new(),
        };
        assert!(result.param_strategies.is_empty());
        assert!(result.insights.is_empty());
    }

    #[test]
    fn test_borrowing_analysis_result_with_strategies() {
        let mut strategies = IndexMap::new();
        strategies.insert("x".to_string(), BorrowingStrategy::TakeOwnership);
        let result = BorrowingAnalysisResult {
            param_strategies: strategies,
            insights: Vec::new(),
        };
        assert_eq!(result.param_strategies.len(), 1);
        assert!(result.param_strategies.contains_key("x"));
    }

    #[test]
    fn test_borrowing_analysis_result_clone() {
        let result = BorrowingAnalysisResult {
            param_strategies: IndexMap::new(),
            insights: vec![BorrowingInsight::SuggestCopyDerive("T".to_string())],
        };
        let cloned = result.clone();
        assert_eq!(result.insights.len(), cloned.insights.len());
    }

    // Integration tests for analyze_function
    #[test]
    fn test_analyze_function_with_float_param() {
        let mut ctx = BorrowingContext::new(Some(PythonType::Float));
        let type_mapper = TypeMapper::new();

        let func = HirFunction {
            name: "double".to_string(),
            params: smallvec![HirParam::new("x".to_string(), PythonType::Float)],
            ret_type: PythonType::Float,
            body: vec![HirStmt::Return(Some(HirExpr::Binary {
                op: depyler_hir::hir::BinOp::Mul,
                left: Box::new(HirExpr::Var("x".to_string())),
                right: Box::new(HirExpr::Literal(Literal::Float(2.0))),
            }))],
            properties: FunctionProperties::default(),
            annotations: TranspilationAnnotations::default(),
            docstring: None,
        };

        let result = ctx.analyze_function(&func, &type_mapper);
        // Float is Copy, so should be taken by value
        let x_strategy = result.param_strategies.get("x").unwrap();
        assert_eq!(*x_strategy, BorrowingStrategy::TakeOwnership);
    }

    #[test]
    fn test_analyze_function_with_bool_param() {
        let mut ctx = BorrowingContext::new(Some(PythonType::Bool));
        let type_mapper = TypeMapper::new();

        let func = HirFunction {
            name: "negate".to_string(),
            params: smallvec![HirParam::new("b".to_string(), PythonType::Bool)],
            ret_type: PythonType::Bool,
            body: vec![HirStmt::Return(Some(HirExpr::Unary {
                op: depyler_hir::hir::UnaryOp::Not,
                operand: Box::new(HirExpr::Var("b".to_string())),
            }))],
            properties: FunctionProperties::default(),
            annotations: TranspilationAnnotations::default(),
            docstring: None,
        };

        let result = ctx.analyze_function(&func, &type_mapper);
        // Bool is Copy, so should be taken by value
        let b_strategy = result.param_strategies.get("b").unwrap();
        assert_eq!(*b_strategy, BorrowingStrategy::TakeOwnership);
    }

    #[test]
    fn test_analyze_function_empty_body() {
        let mut ctx = BorrowingContext::new(None);
        let type_mapper = TypeMapper::new();

        let func = HirFunction {
            name: "noop".to_string(),
            params: smallvec![HirParam::new("x".to_string(), PythonType::Int)],
            ret_type: PythonType::None,
            body: vec![],
            properties: FunctionProperties::default(),
            annotations: TranspilationAnnotations::default(),
            docstring: None,
        };

        let result = ctx.analyze_function(&func, &type_mapper);
        // Even without usage, integer should be taken by value
        assert!(result.param_strategies.contains_key("x"));
    }

    #[test]
    fn test_analyze_function_no_params() {
        let mut ctx = BorrowingContext::new(Some(PythonType::Int));
        let type_mapper = TypeMapper::new();

        let func = HirFunction {
            name: "get_zero".to_string(),
            params: smallvec![],
            ret_type: PythonType::Int,
            body: vec![HirStmt::Return(Some(HirExpr::Literal(Literal::Int(0))))],
            properties: FunctionProperties::default(),
            annotations: TranspilationAnnotations::default(),
            docstring: None,
        };

        let result = ctx.analyze_function(&func, &type_mapper);
        assert!(result.param_strategies.is_empty());
    }

    #[test]
    fn test_analyze_function_multiple_params() {
        let mut ctx = BorrowingContext::new(Some(PythonType::Int));
        let type_mapper = TypeMapper::new();

        let func = HirFunction {
            name: "add".to_string(),
            params: smallvec![
                HirParam::new("a".to_string(), PythonType::Int),
                HirParam::new("b".to_string(), PythonType::Int)
            ],
            ret_type: PythonType::Int,
            body: vec![HirStmt::Return(Some(HirExpr::Binary {
                op: depyler_hir::hir::BinOp::Add,
                left: Box::new(HirExpr::Var("a".to_string())),
                right: Box::new(HirExpr::Var("b".to_string())),
            }))],
            properties: FunctionProperties::default(),
            annotations: TranspilationAnnotations::default(),
            docstring: None,
        };

        let result = ctx.analyze_function(&func, &type_mapper);
        assert_eq!(result.param_strategies.len(), 2);
        assert!(result.param_strategies.contains_key("a"));
        assert!(result.param_strategies.contains_key("b"));
    }

    // === DEPYLER-COVERAGE-95: Additional tests for untested components ===

    #[test]
    fn test_analysis_context_loop_debug() {
        let ctx = AnalysisContext::Loop;
        let debug = format!("{:?}", ctx);
        assert!(debug.contains("Loop"));
    }

    #[test]
    fn test_analysis_context_conditional_debug() {
        let ctx = AnalysisContext::Conditional;
        let debug = format!("{:?}", ctx);
        assert!(debug.contains("Conditional"));
    }

    #[test]
    fn test_analysis_context_closure_debug() {
        let ctx = AnalysisContext::Closure {
            captures: HashSet::from(["x".to_string(), "y".to_string()]),
        };
        let debug = format!("{:?}", ctx);
        assert!(debug.contains("Closure"));
        assert!(debug.contains("captures"));
    }

    #[test]
    fn test_analysis_context_function_debug() {
        let ctx = AnalysisContext::Function;
        let debug = format!("{:?}", ctx);
        assert!(debug.contains("Function"));
    }

    #[test]
    fn test_analysis_context_clone() {
        let ctx = AnalysisContext::Closure {
            captures: HashSet::from(["var".to_string()]),
        };
        let cloned = ctx.clone();
        if let AnalysisContext::Closure { captures } = cloned {
            assert!(captures.contains("var"));
        } else {
            panic!("Expected Closure variant");
        }
    }

    #[test]
    fn test_borrowing_context_debug() {
        let ctx = BorrowingContext::new(None);
        let debug = format!("{:?}", ctx);
        assert!(debug.contains("BorrowingContext"));
    }

    #[test]
    fn test_borrowing_context_initial_state() {
        let ctx = BorrowingContext::new(Some(PythonType::String));
        assert!(ctx.param_usage.is_empty());
        assert!(ctx.moved_vars.is_empty());
        assert!(ctx.mut_borrowed_vars.is_empty());
        assert!(ctx.immut_borrowed_vars.is_empty());
        assert!(!ctx.context_stack.is_empty()); // Should have Function context
    }

    #[test]
    fn test_parameter_usage_pattern_all_fields() {
        let mut pattern = ParameterUsagePattern {
            is_read: true,
            is_mutated: true,
            is_moved: false,
            escapes_through_return: true,
            is_stored: false,
            used_in_closure: true,
            used_in_loop: true,
            ..Default::default()
        };
        pattern.field_accesses.insert("name".to_string());
        pattern.method_calls.insert("len".to_string());

        assert!(pattern.is_read);
        assert!(pattern.is_mutated);
        assert!(!pattern.is_moved);
        assert!(pattern.escapes_through_return);
        assert!(!pattern.is_stored);
        assert!(pattern.used_in_closure);
        assert!(pattern.used_in_loop);
        assert!(pattern.field_accesses.contains("name"));
        assert!(pattern.method_calls.contains("len"));
    }

    #[test]
    fn test_parameter_usage_pattern_debug() {
        let pattern = ParameterUsagePattern::default();
        let debug = format!("{:?}", pattern);
        assert!(debug.contains("ParameterUsagePattern"));
        assert!(debug.contains("is_read"));
    }

    #[test]
    fn test_usage_site_all_fields() {
        let site = UsageSite {
            usage_type: UsageType::Write,
            in_loop: true,
            in_conditional: false,
            borrow_depth: 2,
        };
        assert!(matches!(site.usage_type, UsageType::Write));
        assert!(site.in_loop);
        assert!(!site.in_conditional);
        assert_eq!(site.borrow_depth, 2);
    }

    #[test]
    fn test_usage_site_debug() {
        let site = UsageSite {
            usage_type: UsageType::Read,
            in_loop: false,
            in_conditional: true,
            borrow_depth: 0,
        };
        let debug = format!("{:?}", site);
        assert!(debug.contains("UsageSite"));
        assert!(debug.contains("Read"));
    }

    #[test]
    fn test_usage_type_read_eq() {
        assert_eq!(UsageType::Read, UsageType::Read);
        assert_ne!(UsageType::Read, UsageType::Write);
    }

    #[test]
    fn test_usage_type_closure_variants() {
        let by_value = UsageType::Closure {
            captures_by_value: true,
        };
        let by_ref = UsageType::Closure {
            captures_by_value: false,
        };
        assert_ne!(by_value, by_ref);
    }

    #[test]
    fn test_borrowing_strategy_eq() {
        assert_eq!(
            BorrowingStrategy::TakeOwnership,
            BorrowingStrategy::TakeOwnership
        );
        assert_ne!(
            BorrowingStrategy::TakeOwnership,
            BorrowingStrategy::BorrowMutable { lifetime: None }
        );
    }

    #[test]
    fn test_borrowing_strategy_debug_all() {
        let strategies = [
            BorrowingStrategy::TakeOwnership,
            BorrowingStrategy::BorrowImmutable { lifetime: None },
            BorrowingStrategy::BorrowImmutable {
                lifetime: Some("a".to_string()),
            },
            BorrowingStrategy::BorrowMutable { lifetime: None },
            BorrowingStrategy::UseCow {
                lifetime: "b".to_string(),
            },
            BorrowingStrategy::UseSharedOwnership {
                is_thread_safe: true,
            },
        ];
        for strategy in strategies {
            let debug = format!("{:?}", strategy);
            assert!(!debug.is_empty());
        }
    }

    #[test]
    fn test_borrowing_insight_debug_all() {
        let insights = [
            BorrowingInsight::UnnecessaryMove("x".to_string()),
            BorrowingInsight::LifetimeOptimization {
                param: "p".to_string(),
                suggestion: "Consider borrow".to_string(),
            },
            BorrowingInsight::SuggestCopyDerive("y".to_string()),
            BorrowingInsight::PotentialBorrowConflict {
                param: "z".to_string(),
                locations: vec!["line 1".to_string(), "line 2".to_string()],
            },
        ];
        for insight in insights {
            let debug = format!("{:?}", insight);
            assert!(!debug.is_empty());
        }
    }

    #[test]
    fn test_borrowing_analysis_result_debug() {
        let result = BorrowingAnalysisResult {
            param_strategies: IndexMap::new(),
            insights: vec![],
        };
        let debug = format!("{:?}", result);
        assert!(debug.contains("BorrowingAnalysisResult"));
    }

    #[test]
    fn test_borrowing_analysis_result_with_insights() {
        let result = BorrowingAnalysisResult {
            param_strategies: IndexMap::new(),
            insights: vec![
                BorrowingInsight::SuggestCopyDerive("val".to_string()),
                BorrowingInsight::LifetimeOptimization {
                    param: "p".to_string(),
                    suggestion: "Borrow instead".to_string(),
                },
            ],
        };
        assert_eq!(result.insights.len(), 2);
    }
}
