"""
Helper Functions for Data Service

This module contains private helper functions used by DataService for:
- Parsing API responses
- Processing demographics

These are separated for better code organization and testability.
"""

import logging
from collections import defaultdict
from typing import Any, Dict, List

logger = logging.getLogger(__name__)


def _extract_breakdown_results(demo_data: Dict) -> List[Dict[str, Any]]:
    """Pull results[] from Meta insights total_value.breakdowns[0]."""
    try:
        data = demo_data.get('data', [])
        if not data:
            return []
        breakdowns = data[0].get('total_value', {}).get('breakdowns', [])
        if not breakdowns:
            return []
        return breakdowns[0].get('results', []) or []
    except (KeyError, IndexError, TypeError):
        return []


def process_age_gender_follower_demographics(profile, demo_data: Dict) -> bool:
    """
    Parse follower_demographics with breakdowns age,gender.

    Fills audience_age_distribution, audience_gender_distribution, female/male %.
    Returns True if any row was applied.
    """
    results = _extract_breakdown_results(demo_data)
    if not results:
        return False

    age_totals: Dict[str, float] = defaultdict(float)
    gender_totals: Dict[str, float] = defaultdict(float)
    total = 0.0

    for item in results:
        dims = item.get('dimension_values') or []
        val = float(item.get('value') or 0)
        if val <= 0:
            continue
        if len(dims) >= 2:
            age_bucket, gender = str(dims[0]), str(dims[1])
            age_totals[age_bucket] += val
            gender_totals[gender] += val
            total += val

    if total <= 0:
        return False

    profile.audience_age_distribution = {
        k: round(v / total * 100, 2) for k, v in age_totals.items()
    }
    profile.audience_gender_distribution = {
        k: round(v / total * 100, 2) for k, v in gender_totals.items()
    }

    fm_total = gender_totals.get('F', 0) + gender_totals.get('M', 0)
    if fm_total > 0:
        profile.female_audience_percentage = round(
            gender_totals.get('F', 0) / fm_total * 100, 2
        )
        profile.male_audience_percentage = round(
            gender_totals.get('M', 0) / fm_total * 100, 2
        )

    return True


def process_location_follower_demographics(profile, demo_data: Dict, kind: str) -> None:
    """
    Parse follower_demographics with a single-dimension breakdown: country or city.

    kind: 'country' | 'city'
    """
    if kind not in ('country', 'city'):
        return

    results = _extract_breakdown_results(demo_data)
    if not results:
        return

    total = sum(float(item.get('value') or 0) for item in results)
    if total <= 0:
        return

    rows: List[Dict[str, Any]] = []
    for item in results:
        dims = item.get('dimension_values') or []
        val = float(item.get('value') or 0)
        if not dims or val <= 0:
            continue
        name = str(dims[0])
        rows.append({
            'name': name,
            'percentage': round(val / total * 100, 2),
        })

    rows.sort(key=lambda x: x['percentage'], reverse=True)
    rows = rows[:45]

    if kind == 'country':
        profile.audience_top_countries = rows
    else:
        profile.audience_top_cities = rows


def process_reached_age_only(profile, demo_data: Dict) -> None:
    """Use reached_audience_demographics (age only) if follower age is missing."""
    if profile.audience_age_distribution:
        return

    results = _extract_breakdown_results(demo_data)
    if not results:
        return

    age_totals: Dict[str, float] = defaultdict(float)
    total = 0.0
    for item in results:
        dims = item.get('dimension_values') or []
        val = float(item.get('value') or 0)
        if len(dims) >= 1 and val > 0:
            age_totals[str(dims[0])] += val
            total += val

    if total <= 0:
        return

    profile.audience_age_distribution = {
        k: round(v / total * 100, 2) for k, v in age_totals.items()
    }


def rebuild_audience_summary_from_structured(profile) -> None:
    """Build a readable summary from JSON demographic fields (real data)."""
    parts: List[str] = []

    if profile.audience_top_cities:
        top = profile.audience_top_cities[:5]
        parts.append(
            'Top cities: ' + ', '.join(
                f"{x['name']} {float(x['percentage']):.0f}%" for x in top
            )
        )
    if profile.audience_top_countries:
        top = profile.audience_top_countries[:5]
        parts.append(
            'Top countries: ' + ', '.join(
                f"{x['name']} {float(x['percentage']):.0f}%" for x in top
            )
        )
    if profile.audience_age_distribution:
        ages = sorted(
            profile.audience_age_distribution.items(),
            key=lambda kv: kv[1],
            reverse=True,
        )[:6]
        parts.append(
            'Age: ' + ', '.join(f"{k} {v:.0f}%" for k, v in ages)
        )
    if profile.audience_gender_distribution:
        g = profile.audience_gender_distribution
        gparts = [f"{k} {float(v):.0f}%" for k, v in sorted(g.items())]
        if gparts:
            parts.append('Gender: ' + ', '.join(gparts))

    if parts:
        profile.audience_summary_string = '. '.join(parts) + '.'
    elif profile.female_audience_percentage or profile.male_audience_percentage:
        profile.audience_summary_string = 'Follower demographics synced (gender and age where available).'


def parse_media_insights(insights_data: Dict) -> Dict:
    """
    Parse insights data from Instagram API response.

    Args:
        insights_data: Raw insights data from API

    Returns:
        dict: Parsed insights with numeric values
    """
    parsed = {
        'impressions': 0,
        'reach': 0,
        'engagement': 0,
        'saved': 0,
        'video_views': None
    }

    for insight in insights_data.get('data', []):
        metric_name = insight.get('name')
        value = insight.get('values', [{}])[0].get('value', 0)

        if metric_name in parsed:
            parsed[metric_name] = value

    return parsed


# Backwards compatibility: older code imported this name
def process_follower_demographics(profile, demo_data: Dict, label: str = "Follower demographics"):
    """Deprecated path: use process_age_gender_follower_demographics."""
    try:
        if process_age_gender_follower_demographics(profile, demo_data):
            profile.audience_summary_string = f"{label}: data ingested"
    except Exception as exc:
        logger.warning(f"Could not process demographics ({label}): {exc}")
