import json
from pathlib import Path

import pandas as pd
from fastapi import APIRouter, HTTPException

router = APIRouter(prefix="/api", tags=["benefits"])

_DATA_DIR = Path(__file__).parent / "data"

with (_DATA_DIR / "member_insights.json").open() as f:
    _MEMBER_INSIGHTS = json.load(f)

_SCHEDULE_TEXT = (_DATA_DIR / "schedule_response.txt").read_text(encoding="utf-8").strip()

_HISTORICAL = pd.read_csv(_DATA_DIR / "historical_procedures.csv")
_AVAILABLE = pd.read_csv(_DATA_DIR / "available_procedures.csv")


_OPS = {
    "equals": lambda s, v: s == v,
    "ne": lambda s, v: s != v,
    "contains": lambda s, v: s.astype(str).str.contains(str(v), case=False, na=False),
    "gt": lambda s, v: s > v,
    "lt": lambda s, v: s < v,
    "ge": lambda s, v: s >= v,
    "le": lambda s, v: s <= v,
}

_COLUMN_ALIASES = {
    "procedure_name": "procedure",
    "procedurename": "procedure",
    "proc": "procedure",
    "name": "member_name",
    "member": "member_name",
    "membername": "member_name",
    "location_name": "location",
    "provider": "location",
    "facility": "location",
    "rating": "facility_rating",
    "facilityrating": "facility_rating",
    "distance": "distance_miles",
    "plan": "member_plan",
    "memberplan": "member_plan",
    "type": "procedure_type",
    "proceduretype": "procedure_type",
    "cost": "total_cost",
    "totalcost": "total_cost",
    "price": "total_cost",
    "in_network_only": "in_network",
    "innetwork": "in_network",
}

_VALUE_ALIASES = {
    "xray": "X Ray",
    "x-ray": "X Ray",
    "radiografia": "X Ray",
    "radiografía": "X Ray",
    "radiografias": "X Ray",
    "radiografías": "X Ray",
    "resonancia": "MRI",
    "resonancia magnetica": "MRI",
    "resonancia magnética": "MRI",
    "tomografia": "CT Scan",
    "tomografía": "CT Scan",
    "ct": "CT Scan",
    "limpieza dental": "Dental Cleaning",
    "limpieza": "Dental Cleaning",
    "examen visual": "Vision Exam",
    "examen de la vista": "Vision Exam",
    "vision": "Vision Exam",
    "chequeo anual": "Annual Physical Exam",
    "examen anual": "Annual Physical Exam",
    "fisico anual": "Annual Physical Exam",
    "apendicectomia": "Appendectomy",
    "apendicectomía": "Appendectomy",
    "analisis de sangre": "Blood Test",
    "análisis de sangre": "Blood Test",
}


def _normalize_column(col: str, valid_cols: list[str]) -> str | None:
    if col is None:
        return None
    if col in valid_cols:
        return col
    lower = col.lower().replace(" ", "").replace("-", "_")
    if lower in _COLUMN_ALIASES:
        candidate = _COLUMN_ALIASES[lower]
        if candidate in valid_cols:
            return candidate
    return None


def _normalize_value(val):
    if not isinstance(val, str):
        return val
    lower = val.lower().strip()
    if lower in _VALUE_ALIASES:
        return _VALUE_ALIASES[lower]
    return val


def _apply_filters_and_group(df: pd.DataFrame, filters_raw, group_by_raw) -> list[dict]:
    try:
        filters = json.loads(filters_raw) if isinstance(filters_raw, str) else (filters_raw or [])
        group_by = json.loads(group_by_raw) if isinstance(group_by_raw, str) else (group_by_raw or [])
    except json.JSONDecodeError as exc:
        raise HTTPException(status_code=400, detail=f"Invalid JSON in filters or group_by: {exc}")

    valid_cols = list(df.columns)
    result = df.copy()
    for f in filters:
        raw_col, op, val = f.get("column"), f.get("operator"), f.get("value")
        col = _normalize_column(raw_col, valid_cols)
        if col is None:
            raise HTTPException(
                status_code=400,
                detail=f"Unknown column: {raw_col}. Valid columns: {valid_cols}",
            )
        if op not in _OPS:
            raise HTTPException(
                status_code=400,
                detail=f"Unsupported operator: {op}. Valid operators: {list(_OPS.keys())}",
            )
        norm_val = _normalize_value(val)
        result = result[_OPS[op](result[col], norm_val)]

    if group_by:
        norm_group = [_normalize_column(c, valid_cols) for c in group_by]
        missing = [orig for orig, n in zip(group_by, norm_group) if n is None]
        if missing:
            raise HTTPException(
                status_code=400,
                detail=f"Unknown group_by columns: {missing}. Valid columns: {valid_cols}",
            )
        numeric_cols = result.select_dtypes(include="number").columns.tolist()
        result = result.groupby(norm_group)[numeric_cols].mean().reset_index()

    return result.to_dict(orient="records")


@router.get("/member-insights")
def member_insights():
    return _MEMBER_INSIGHTS


@router.get("/schedule")
def schedule():
    return {"result": _SCHEDULE_TEXT}


@router.post("/historical-procedures")
def historical_procedures(payload: dict):
    rows = _apply_filters_and_group(
        _HISTORICAL,
        payload.get("filters", "[]"),
        payload.get("group_by", "[]"),
    )
    return {"result": rows}


@router.post("/available-procedures")
def available_procedures(payload: dict):
    rows = _apply_filters_and_group(
        _AVAILABLE,
        payload.get("filters", "[]"),
        payload.get("group_by", "[]"),
    )
    return {"result": rows}
