import logging
from datetime import datetime
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple

from src.services.campflow import get_campflow_client

if TYPE_CHECKING:
    from src.group_settings.models import GroupConfig

logger = logging.getLogger(__name__)

def _clean_label(name: str) -> str:
    """Make strings lowercase, replace spaces with underscores and replace German umlauts."""
    name = name.lower().replace(" ", "_")
    umlaut_mapping = str.maketrans({"ä": "ae", "ö": "oe", "ü": "ue", "ß": "ss"})
    return name.translate(umlaut_mapping)

def _get_age(birthdate_str: str, event_date_str: str) -> Optional[int]:
    """Calculate age at the time of the event."""
    if not birthdate_str or not event_date_str:
        return None
    try:
        birthdate = datetime.strptime(birthdate_str, "%Y-%m-%d")
        event_date = datetime.fromisoformat(event_date_str.replace("Z", "+00:00"))
        
        age = event_date.year - birthdate.year - ((event_date.month, event_date.day) < (birthdate.month, birthdate.day))
        return age
    except Exception:
        return None

async def fetch_event_tn_data(
    lst_id: str,
    group_config: "GroupConfig | None" = None,
) -> Tuple[List[Dict[str, Any]], List[Dict[str, Any]], Optional[Dict[str, Any]]]:
    """
    Fetches event, participant, and member data from Campflow API,
    flattens it and prepares it for PDF/Stats services.
    """
    logger.info(f"Fetching API data for event list {lst_id}...")
    client = get_campflow_client(group_config)

    # 1. Get Event Info
    events = await client.get_events()
    event_info = next((e for e in events if e.get("list_id") == lst_id), None)
    if not event_info:
        logger.error(f"Event for list_id {lst_id} not found.")
        return [], [], None

    start_date_str = event_info.get("start_date")

    # 2. Get Field Definitions
    fields_data = await client.get_list_custom_columns(lst_id)
    # IDs from Campflow might already start with 'col_'
    field_mapping = {}
    for f in fields_data:
        col_id = str(f["id"])
        if not col_id.startswith("col_"):
            col_id = f"col_{col_id}"
        field_mapping[col_id] = _clean_label(f["name"])

    # 3. Get Participants
    tn_data = await client.get_list_persons(lst_id)
    
    # 4. Get Members (for group leader mapping)
    member_data = await client.get_member_persons()

    # Process Participants
    processed_tn = []
    for person in tn_data:
        # Exclude cancelled persons
        if person.get("cancellation_date"):
            continue

        # Flatten and rename custom fields
        flat_person = {
            "id": person.get("id"),
            "gender": person.get("gender"),
            "birthdate": person.get("birthdate"),
            "name.first_name": person.get("name", {}).get("first_name"),
            "name.last_name": person.get("name", {}).get("last_name"),
            "address.street": person.get("address", {}).get("street"),
            "address.postcode": person.get("address", {}).get("postcode"),
            "address.city": person.get("address", {}).get("city"),
            "address.postal_info": person.get("address", {}).get("postal_info"),
            "email": person.get("email"),
            "mobile": person.get("mobile"),
            "diet": person.get("diet"),
            "intolerances": person.get("intolerances"),
            "health": person.get("health"),
        }

        # Handle custom fields
        for key, value in person.items():
            if not key.startswith("col_"):
                continue
            
            # Check if we have a mapping for this column
            mapped_name = field_mapping.get(key)
            if mapped_name:
                flat_person[mapped_name] = value
            else:
                # If no mapping, keep the col_ name as a fallback
                flat_person[key] = value

        # Calculate age
        flat_person["age_at_event"] = _get_age(person.get("birthdate"), start_date_str)
        
        processed_tn.append(flat_person)

    # Process Leaders
    processed_gf = []
    for member in member_data:
        label_names = member.get("label_names", [])
        if isinstance(label_names, list) and "Gruppenführung" in label_names:
            processed_gf.append({
                "name.first_name": member.get("name", {}).get("first_name"),
                "name.last_name": member.get("name", {}).get("last_name"),
                "is_leader": True
            })

    return processed_tn, processed_gf, event_info
