"""Shared utilities for formatting FHIR common data types."""

from __future__ import annotations

from typing import Any


def format_human_name(names: list[Any] | None) -> str:
    """Format HumanName list to 'Family, Given' string.

    Prefers 'official' or 'usual' use. Returns empty string if no names.
    """
    if not names:
        return ""
    # Prefer official, then usual, then first
    name = None
    for n in names:
        use = _get_attr(n, "use") if hasattr(n, "use") else (n.get("use") if isinstance(n, dict) else None)
        if use in ("official", "usual"):
            name = n
            break
    if name is None:
        name = names[0]

    # Use text if available
    text = _get_attr(name, "text") if hasattr(name, "text") else (name.get("text") if isinstance(name, dict) else None)
    if text:
        return str(text)

    family = _get_attr(name, "family") if hasattr(name, "family") else (name.get("family") if isinstance(name, dict) else None)
    given = _get_attr(name, "given") if hasattr(name, "given") else (name.get("given") if isinstance(name, dict) else None)

    family = family or ""
    if isinstance(given, list):
        given_str = " ".join(str(g) for g in given) if given else ""
    else:
        given_str = str(given) if given else ""

    if family and given_str:
        return f"{family}, {given_str}"
    return family or given_str or ""


def format_codeable_concept(concept: Any | None) -> str:
    """Extract display or code from CodeableConcept. Returns empty string if absent."""
    if concept is None:
        return ""
    codings = _get_attr(concept, "coding") if hasattr(concept, "coding") else (concept.get("coding") if isinstance(concept, dict) else None)
    if not codings:
        text = _get_attr(concept, "text") if hasattr(concept, "text") else (concept.get("text") if isinstance(concept, dict) else None)
        return str(text) if text else ""
    # Prefer first coding with display
    for c in codings:
        display = _get_attr(c, "display") if hasattr(c, "display") else (c.get("display") if isinstance(c, dict) else None)
        if display:
            return str(display)
    # Fallback to code
    first = codings[0]
    code = _get_attr(first, "code") if hasattr(first, "code") else (first.get("code") if isinstance(first, dict) else None)
    return str(code) if code else ""


def format_reference(ref: Any | None) -> str:
    """Extract display or reference from Reference. Returns empty string if absent."""
    if ref is None:
        return ""
    display = _get_attr(ref, "display") if hasattr(ref, "display") else (ref.get("display") if isinstance(ref, dict) else None)
    if display:
        return str(display)
    ref_val = _get_attr(ref, "reference") if hasattr(ref, "reference") else (ref.get("reference") if isinstance(ref, dict) else None)
    return str(ref_val) if ref_val else ""


def format_period(period: Any | None) -> str:
    """Format Period as 'start - end' or 'start'. Returns empty string if absent."""
    if period is None:
        return ""
    start = _get_attr(period, "start") if hasattr(period, "start") else (period.get("start") if isinstance(period, dict) else None)
    end = _get_attr(period, "end") if hasattr(period, "end") else (period.get("end") if isinstance(period, dict) else None)
    if not start:
        return ""
    if end:
        return f"{start} - {end}"
    return str(start)


def format_identifier(identifiers: list[Any] | None) -> list[dict[str, Any]]:
    """Format Identifier list to [{system, value, type}]. Returns empty list if absent."""
    if not identifiers:
        return []
    result = []
    for i in identifiers:
        system = _get_attr(i, "system") if hasattr(i, "system") else (i.get("system") if isinstance(i, dict) else None)
        value = _get_attr(i, "value") if hasattr(i, "value") else (i.get("value") if isinstance(i, dict) else None)
        itype = _get_attr(i, "type") if hasattr(i, "type") else (i.get("type") if isinstance(i, dict) else None)
        type_str = format_codeable_concept(itype) if itype else None
        result.append({
            "system": str(system) if system else None,
            "value": str(value) if value else None,
            "type": type_str,
        })
    return result


def format_telecom(telecoms: list[Any] | None) -> list[dict[str, Any]]:
    """Format ContactPoint list to [{system, value, use}]. Returns empty list if absent."""
    if not telecoms:
        return []
    result = []
    for t in telecoms:
        system = _get_attr(t, "system") if hasattr(t, "system") else (t.get("system") if isinstance(t, dict) else None)
        value = _get_attr(t, "value") if hasattr(t, "value") else (t.get("value") if isinstance(t, dict) else None)
        use = _get_attr(t, "use") if hasattr(t, "use") else (t.get("use") if isinstance(t, dict) else None)
        result.append({
            "system": str(system) if system else None,
            "value": str(value) if value else None,
            "use": str(use) if use else None,
        })
    return result


def format_address(addresses: list[Any] | Any | None) -> list[dict[str, Any]]:
    """Format Address list to flattened dicts. Accepts single Address or list. Returns empty list if absent."""
    if addresses is None:
        return []
    if not isinstance(addresses, list):
        addresses = [addresses]
    if not addresses:
        return []
    result = []
    for a in addresses:
        line = _get_attr(a, "line") if hasattr(a, "line") else (a.get("line") if isinstance(a, dict) else None)
        if isinstance(line, list):
            line = ", ".join(str(x) for x in line) if line else None
        city = _get_attr(a, "city") if hasattr(a, "city") else (a.get("city") if isinstance(a, dict) else None)
        state = _get_attr(a, "state") if hasattr(a, "state") else (a.get("state") if isinstance(a, dict) else None)
        postal = _get_attr(a, "postalCode") if hasattr(a, "postalCode") else (a.get("postalCode") if isinstance(a, dict) else None)
        country = _get_attr(a, "country") if hasattr(a, "country") else (a.get("country") if isinstance(a, dict) else None)
        use = _get_attr(a, "use") if hasattr(a, "use") else (a.get("use") if isinstance(a, dict) else None)
        text = _get_attr(a, "text") if hasattr(a, "text") else (a.get("text") if isinstance(a, dict) else None)
        result.append({
            "line": line,
            "city": str(city) if city else None,
            "state": str(state) if state else None,
            "postalCode": str(postal) if postal else None,
            "country": str(country) if country else None,
            "use": str(use) if use else None,
            "text": str(text) if text else None,
        })
    return result


def _get_attr(obj: Any, name: str) -> Any:
    """Safely get attribute; return None if missing."""
    try:
        return getattr(obj, name, None)
    except Exception:
        return None
