"""Helper functions for web route handlers.

This module contains extracted helper functions to reduce complexity in routes.py.
Following the Single Responsibility Principle and DRY patterns.
"""
from flask import current_app, Response, flash, redirect, url_for, make_response, render_template
from whatsthedamage.view.forms import UploadForm
from whatsthedamage.services.processing_service import ProcessingService
from whatsthedamage.services.validation_service import ValidationService
from whatsthedamage.services.response_builder_service import ResponseBuilderService
from whatsthedamage.services.session_service import SessionService
from whatsthedamage.services.data_formatting_service import DataFormattingService
from whatsthedamage.services.file_upload_service import FileUploadService, FileUploadError
from whatsthedamage.services.cache_service import CacheService
from whatsthedamage.services.statistical_analysis_service import StatisticalAnalysisService
from whatsthedamage.services.id_mapping_service import IdMappingService
from whatsthedamage.services.drilldown_service import DrilldownService
from whatsthedamage.models.dt_models import ProcessingResponse
from whatsthedamage.utils.flask_locale import get_default_language
from typing import Dict, Callable, Optional, cast, Tuple, List, Any, Union


def _get_processing_service() -> ProcessingService:
    """Get processing service from app extensions (dependency injection)."""
    return cast(ProcessingService, current_app.extensions['processing_service'])


def _get_validation_service() -> ValidationService:
    """Get validation service from app extensions (dependency injection)."""
    return cast(ValidationService, current_app.extensions['validation_service'])


def _get_response_builder_service() -> ResponseBuilderService:
    """Get response builder service from app extensions (dependency injection)."""
    return cast(ResponseBuilderService, current_app.extensions['response_builder_service'])

def _get_id_mapping_service() -> 'IdMappingService':
    """Get ID mapping service from app extensions (dependency injection)."""
    from whatsthedamage.services.id_mapping_service import IdMappingService
    return cast(IdMappingService, current_app.extensions['id_mapping_service'])


def _get_file_upload_service() -> FileUploadService:
    """Get file upload service from app extensions (dependency injection)."""
    return cast(FileUploadService, current_app.extensions['file_upload_service'])


def _get_session_service() -> SessionService:
    """Get session service from app extensions (dependency injection)."""
    return cast(SessionService, current_app.extensions['session_service'])


def _get_data_formatting_service() -> DataFormattingService:
    """Get data formatting service from app extensions (dependency injection)."""
    return cast(DataFormattingService, current_app.extensions['data_formatting_service'])


def _get_cache_service() -> CacheService:
    """Get cache service from app extensions (dependency injection)."""
    return cast(CacheService, current_app.extensions['cache_service'])

def _get_statistical_analysis_service() -> StatisticalAnalysisService:
    """Get statistical analysis service from app extensions (dependency injection)."""
    return cast(StatisticalAnalysisService, current_app.extensions['statistical_analysis_service'])

def _get_drilldown_service() -> DrilldownService:
    """Get drilldown service from app extensions (dependency injection)."""
    from whatsthedamage.services.drilldown_service import DrilldownService
    return cast(DrilldownService, current_app.extensions['drilldown_service'])


def handle_file_uploads(form: UploadForm) -> Dict[str, str]:
    """Handle file uploads using FileUploadService.

    Args:
        form: The validated upload form containing file data

    Returns:
        Dict with 'csv_path' and 'config_path' (empty string if no config)

    Raises:
        ValueError: If file validation or save fails
    """
    upload_folder: str = current_app.config['UPLOAD_FOLDER']
    file_upload_service = _get_file_upload_service()

    try:
        # Extract config file or None
        config_file = form.config.data if form.config.data else None

        # Use FileUploadService to save files
        csv_path, config_path = file_upload_service.save_files(
            form.filename.data,
            upload_folder,
            config_file=config_file
        )

        return {
            'csv_path': csv_path,
            'config_path': config_path or ''
        }
    except FileUploadError as e:
        raise ValueError(str(e))


def process_details_and_build_response(
    form: UploadForm,
    csv_path: str,
    clear_upload_folder_fn: Callable[[], None],
    config_path: Optional[str]
) -> Response:
    """Process CSV for details view and build HTML response.

    Args:
        form: The upload form with processing parameters
        csv_path: Path to CSV file
        clear_upload_folder_fn: Function to clear upload folder after processing

    Returns:
        Flask response with rendered result.html
    """
    # Process using service layer
    session_service = SessionService()
    language = session_service.get_language() or get_default_language()
    result = _get_processing_service().process_with_details(
        csv_file_path=csv_path,
        config_file_path=config_path,
        start_date=form.start_date.data.strftime('%Y-%m-%d') if form.start_date.data else None,
        end_date=form.end_date.data.strftime('%Y-%m-%d') if form.end_date.data else None,
        ml_enabled=form.ml.data,
        category_filter=form.filter.data,
        language=language
    )

    # Extract Dict[str, DataTablesResponse] from result
    dt_responses_by_account = result.data
    result_id = result.result_id
    statistical_metadata = result.statistical_metadata

    # Cache result at controller layer (separation of concerns)
    # Business logic (ProcessingService) doesn't know about caching
    cache_service = _get_cache_service()
    cache_service.set(result_id, result)

    # Prepare accounts data for template rendering
    formatting_service = _get_data_formatting_service()
    accounts_data = formatting_service.prepare_accounts_for_template(
        dt_responses_by_account,
        statistical_metadata
    )

    # Generate secure drill-down URLs for each account using DrilldownService
    drilldown_urls_by_account = {}
    drilldown_service = _get_drilldown_service()
    for account_id, dt_response in dt_responses_by_account.items():
        drilldown_urls_by_account[account_id] = drilldown_service.generate_drilldown_urls(
            result_id, account_id, dt_response
        )

    # Pass the prepared data to template for multi-account rendering
    clear_upload_folder_fn()

    return make_response(
        render_template(
            'results.html',
            accounts_data=accounts_data,
            result_id=result_id,
            drilldown_urls_by_account=drilldown_urls_by_account
        )
    )


def handle_entity_drilldown(
    result_id: str,
    account_id: str,
    entity_id: str,
    entity_type: str,
    template: str,
    data_not_found_error: str = 'Data not found',
    index_route: str = 'main.index'
) -> Union[Response, Any]:
    """Unified handler for category and month entity drilldown requests.

    Eliminates code duplication between show_month_categories() and show_category_months()
    by providing a single implementation with configurable entity type and filtering.

    Args:
        result_id: UUID of the cached processing result
        account_id: Secure account ID
        entity_id: Secure entity ID (category_id or month_id)
        entity_type: Type of entity ('category' or 'month')
        template: Template name to render
        filter_key: Key to use for filtering (e.g., 'category' or 'date.timestamp')
        data_not_found_error: Error message for missing data
        index_route: Route to redirect on error

    Returns:
        Flask Response with rendered template or redirect

    Example:
        >>> # For category drilldown:
        >>> handle_entity_drilldown(
        >>>     result_id, account_id, category_id,
        >>>     'category', 'category_months_list.html', 'category'
        >>> )
        >>>
        >>> # For month drilldown:
        >>> handle_entity_drilldown(
        >>>     result_id, account_id, month_id,
        >>>     'month', 'month_categories_list.html', 'date.timestamp'
        >>> )
    """
    # Use DrilldownService for all business logic
    drilldown_service = _get_drilldown_service()

    # Resolve IDs to original values using service
    resolution = drilldown_service.resolve_entity_ids(result_id, account_id, entity_id, entity_type)

    if resolution['error']:
        flash(resolution['error'], 'danger')
        return redirect(url_for(index_route))

    account_number = resolution['account_number']
    entity_name = resolution['entity_name']
    filter_value = resolution['filter_value']

    # Get cached data using service
    cache_result = drilldown_service.get_cached_data_for_account(result_id, account_number)

    if cache_result['error']:
        flash(cache_result['error'], 'danger')
        return redirect(url_for(index_route))

    dt_response = cache_result['dt_response']

    # Filter data for the specific entity using service
    filtered_data = drilldown_service.filter_data_for_entity(dt_response, entity_type, filter_value)

    if not filtered_data:
        flash(data_not_found_error, 'danger')
        return redirect(url_for(index_route))

    # Generate drilldown URLs using service
    drilldown_urls = drilldown_service.generate_drilldown_urls(result_id, account_number, dt_response)

    # Build context using service
    context = drilldown_service.build_drilldown_context(
        filtered_data=filtered_data,
        account_number=account_number,
        result_id=result_id,
        account_id=account_id,
        entity_type=entity_type,
        entity_id=entity_id,
        entity_name=entity_name,
        drilldown_urls=drilldown_urls
    )

    return make_response(render_template(template, **context))

def handle_recalculate_statistics_request(
    result_id: str,
    algorithms: List[str],
    direction: str,
) -> Tuple[Dict[str, Any], int]:
    """Handle recalculate statistics request with business logic.

    This helper function contains the business logic for recalculating statistical
    highlights, following the pattern of other helper functions in this module.

    Args:
        result_id: UUID of the cached processing result
        algorithms: List of algorithm names to use (e.g., ['iqr', 'pareto'])
        direction: Analysis direction ('columns' or 'rows')
        use_default_directions: If True, use each algorithm's default direction instead of the provided direction

    Returns:
        Tuple of (response_data, status_code)
        On success: (dict with highlights and metadata, 200)
        On error: (dict with error message, appropriate status code)

    Example:
        >>> response_data, status_code = handle_recalculate_statistics_request(
        >>>     result_id='abc123',
        >>>     algorithms=['iqr', 'pareto'],
        >>>     direction='columns'
        >>> )
    """
    try:
        # Get cached data
        cache_service = _get_cache_service()
        cached = cache_service.get(result_id)
        if not cached:
            return {'error': 'Result not found or expired'}, 404

        # Recalculate highlights using statistical analysis service
        stat_service = _get_statistical_analysis_service()
        new_statistical_metadata = stat_service.compute_statistical_metadata(
            cached.data,
            algorithms=algorithms,
            direction=direction
        )

        # Update cache with new metadata
        updated_cached = ProcessingResponse(
            result_id=cached.result_id,
            data=cached.data,
            metadata=cached.metadata,
            statistical_metadata=new_statistical_metadata
        )
        cache_service.set(result_id, updated_cached)

        # Convert highlights to dictionary format for easier frontend processing
        formatting_service = _get_data_formatting_service()
        highlights_dict = formatting_service._convert_metadata_to_highlights_dict(
            new_statistical_metadata
        )

        return {
            'status': 'success',
            'highlights': highlights_dict,
            'message': 'Statistics recalculated successfully'
        }, 200

    except Exception as e:
        return {'error': str(e)}, 500
