"""Validation utilities for financial data and inputs."""

from typing import List, Dict, Any, Tuple
from datetime import date

from .financial_calc import Debt, Income, RecurringExpense, FutureIncome


class ValidationError(ValueError):
    """Custom exception for validation errors."""
    pass


def validate_debt_data(debt_data: Dict[str, Any]) -> List[str]:
    """Validate debt data dictionary.
    
    Args:
        debt_data: Dictionary containing debt information
        
    Returns:
        List of validation error messages (empty if valid)
    """
    errors = []
    
    # Required fields
    required_fields = ['name', 'balance', 'minimum_payment', 'interest_rate', 'due_date']
    for field in required_fields:
        if field not in debt_data or debt_data[field] is None:
            errors.append(f"Missing required field: {field}")
    
    # Validate numeric fields
    if 'balance' in debt_data:
        try:
            balance = float(debt_data['balance'])
            if balance < 0:
                errors.append("Balance cannot be negative")
        except (ValueError, TypeError):
            errors.append("Balance must be a valid number")
    
    if 'minimum_payment' in debt_data:
        try:
            min_payment = float(debt_data['minimum_payment'])
            if min_payment < 0:
                errors.append("Minimum payment cannot be negative")
        except (ValueError, TypeError):
            errors.append("Minimum payment must be a valid number")
    
    if 'interest_rate' in debt_data:
        try:
            interest_rate = float(debt_data['interest_rate'])
            if interest_rate < 0 or interest_rate > 100:
                errors.append("Interest rate must be between 0 and 100")
        except (ValueError, TypeError):
            errors.append("Interest rate must be a valid number")
    
    if 'due_date' in debt_data:
        try:
            due_date = int(debt_data['due_date'])
            if due_date < 1 or due_date > 31:
                errors.append("Due date must be between 1 and 31")
        except (ValueError, TypeError):
            errors.append("Due date must be a valid integer")
    
    return errors


def validate_income_data(income_data: Dict[str, Any]) -> List[str]:
    """Validate income data dictionary.
    
    Args:
        income_data: Dictionary containing income information
        
    Returns:
        List of validation error messages (empty if valid)
    """
    errors = []
    
    # Required fields
    required_fields = ['source', 'amount', 'frequency']
    for field in required_fields:
        if field not in income_data or income_data[field] is None:
            errors.append(f"Missing required field: {field}")
    
    # Validate amount
    if 'amount' in income_data:
        try:
            amount = float(income_data['amount'])
            if amount <= 0:
                errors.append("Income amount must be positive")
        except (ValueError, TypeError):
            errors.append("Income amount must be a valid number")
    
    # Validate frequency
    if 'frequency' in income_data:
        valid_frequencies = ['weekly', 'bi-weekly', 'monthly', 'quarterly', 'annually']
        frequency = str(income_data['frequency']).lower().strip()
        if frequency not in valid_frequencies:
            errors.append(f"Invalid frequency. Must be one of: {', '.join(valid_frequencies)}")
    
    return errors


def validate_expense_data(expense_data: Dict[str, Any]) -> List[str]:
    """Validate expense data dictionary.
    
    Args:
        expense_data: Dictionary containing expense information
        
    Returns:
        List of validation error messages (empty if valid)
    """
    errors = []
    
    # Required fields
    required_fields = ['description', 'amount', 'frequency']
    for field in required_fields:
        if field not in expense_data or expense_data[field] is None:
            errors.append(f"Missing required field: {field}")
    
    # Validate amount
    if 'amount' in expense_data:
        try:
            amount = float(expense_data['amount'])
            if amount <= 0:
                errors.append("Expense amount must be positive")
        except (ValueError, TypeError):
            errors.append("Expense amount must be a valid number")
    
    # Validate frequency
    if 'frequency' in expense_data:
        valid_frequencies = ['weekly', 'bi-weekly', 'monthly', 'quarterly', 'annually']
        frequency = str(expense_data['frequency']).lower().strip()
        if frequency not in valid_frequencies:
            errors.append(f"Invalid frequency. Must be one of: {', '.join(valid_frequencies)}")
    
    return errors


def validate_financial_scenario(
    debts: List[Debt],
    income_sources: List[Income],
    recurring_expenses: List[RecurringExpense],
    settings: Dict[str, Any]
) -> Tuple[bool, List[str]]:
    """Validate a complete financial scenario for logical consistency.
    
    Args:
        debts: List of debt objects
        income_sources: List of income objects  
        recurring_expenses: List of recurring expense objects
        settings: Settings dictionary
        
    Returns:
        Tuple of (is_valid, error_messages)
    """
    errors = []
    warnings = []
    
    # Check if we have debts
    if not debts:
        errors.append("No debts provided - nothing to optimize")
    
    # Check if we have income
    if not income_sources:
        errors.append("No income sources provided")
    
    # Calculate totals for validation
    if debts and income_sources:
        total_debt = sum(debt.balance for debt in debts)
        total_minimum_payments = sum(debt.minimum_payment for debt in debts)
        total_monthly_income = sum(income.get_monthly_amount() for income in income_sources)
        total_monthly_expenses = sum(expense.get_monthly_amount() for expense in recurring_expenses)
        
        # Check basic financial viability
        if total_monthly_income < total_minimum_payments:
            errors.append(
                f"Monthly income (${total_monthly_income:.2f}) is less than "
                f"minimum debt payments (${total_minimum_payments:.2f})"
            )
        
        available_cashflow = total_monthly_income - total_minimum_payments - total_monthly_expenses
        if available_cashflow < 0:
            errors.append(
                f"Insufficient cash flow: Monthly income (${total_monthly_income:.2f}) "
                f"minus minimum payments (${total_minimum_payments:.2f}) "
                f"minus expenses (${total_monthly_expenses:.2f}) "
                f"= ${available_cashflow:.2f}"
            )
        
        # Warnings for potential issues
        if total_debt > total_monthly_income * 60:  # More than 5 years of income in debt
            warnings.append(f"Very high debt-to-income ratio: ${total_debt:.2f} debt vs ${total_monthly_income:.2f} monthly income")
        
        if available_cashflow < 100:
            warnings.append(f"Very tight cash flow: Only ${available_cashflow:.2f} available after minimums and expenses")
    
    # Validate settings
    if 'current_bank_balance' in settings:
        try:
            bank_balance = float(settings['current_bank_balance'])
            if bank_balance < 0:
                warnings.append("Negative bank balance may cause cash flow issues")
        except (ValueError, TypeError):
            errors.append("Invalid bank balance in settings")
    
    is_valid = len(errors) == 0
    all_messages = errors + [f"Warning: {w}" for w in warnings]
    
    return is_valid, all_messages


def validate_optimization_goal(goal: str) -> bool:
    """Validate optimization goal string.
    
    Args:
        goal: Goal string to validate
        
    Returns:
        True if valid, False otherwise
    """
    valid_goals = ['minimize_interest', 'minimize_time', 'maximize_cashflow']
    return goal.lower() in valid_goals