import csv
import logging
from datetime import datetime, timedelta

from django.contrib.auth import get_user_model

from scrobbles.models import Scrobble
from scrobbles.notifications import ScrobbleNtfyNotification
from tasks.models import Task

logger = logging.getLogger(__name__)

FLOAT_COLUMNS = {
    "WEIGHT": "weight",
    "BMI": "bmi",
    "BODY_FAT": "body_fat",
    "BONE": "bone",
    "MUSCLE": "muscle",
    "WATER": "water",
    "VISCERAL_FAT": "visceral_fat",
    "WAIST": "waist",
    "CALORIES": "calories",
    "BMR": "bmr",
    "TDEE": "tdee",
    "HEART_RATE": "heart_rate",
    "CHEST": "chest",
    "BICEPS": "biceps",
    "NECK": "neck",
    "THIGH": "thigh",
    "HIPS": "hips",
    "CALIPER": "caliper",
    "CALIPER_1": "caliper_1",
    "CALIPER_2": "caliper_2",
    "CALIPER_3": "caliper_3",
    "LBM": "lbm",
    "WHR": "whr",
    "WHTR": "whtr",
}


def parse_float(value):
    if not value:
        return None
    try:
        return round(float(value), 2)
    except (ValueError, TypeError):
        return None


def import_scale_csv(file_path, user_id):
    user = get_user_model().objects.get(id=user_id)
    weigh_in = Task.find_or_create("Weigh-in")
    new_scrobbles = []

    with open(file_path, newline="", encoding="utf-8-sig") as f:
        reader = csv.DictReader(f)
        for row in reader:
            date_str = (row.get("DATE") or "").strip()
            time_str = (row.get("TIME") or "").strip()
            if not date_str or not time_str:
                logger.warning("Skipping row with no DATE or TIME")
                continue

            try:
                dt = datetime.strptime(f"{date_str} {time_str}", "%Y-%m-%d %H:%M:%S.%f")
            except ValueError:
                try:
                    dt = datetime.strptime(f"{date_str} {time_str}", "%Y-%m-%d %H:%M:%S")
                except ValueError:
                    logger.warning(f"Could not parse date/time: {date_str} {time_str}")
                    continue

            dt = dt.replace(microsecond=0)
            stop = user.profile.get_timestamp_with_tz(dt)
            start = stop - timedelta(minutes=5)

            log_dict = {}
            for csv_col, log_key in FLOAT_COLUMNS.items():
                val = parse_float(row.get(csv_col))
                if val is not None:
                    log_dict[log_key] = val

            comment = (row.get("COMMENT") or "").strip()
            if comment:
                log_dict["comment"] = comment

            log_dict["unit_type"] = user.profile.weigh_in_units

            weight_val = log_dict.get("weight")
            if weight_val is not None:
                unit = "kg" if user.profile.weigh_in_units == "metric" else "lbs"
                log_dict["title"] = f"{weight_val} {unit}"

            existing = Scrobble.objects.filter(
                timestamp=start,
                task=weigh_in,
                user=user,
            ).first()
            if existing:
                logger.debug(f"Skipping existing scrobble for {start}")
                continue

            new_scrobble = Scrobble(
                user=user,
                timestamp=start,
                stop_timestamp=stop,
                timezone=stop.tzinfo.name,
                source="openScale CSV Import",
                task=weigh_in,
                log=log_dict,
                played_to_completion=True,
                in_progress=False,
                media_type=Scrobble.MediaType.TASK,
                visibility="private",
            )
            new_scrobbles.append(new_scrobble)

    created = Scrobble.objects.bulk_create(new_scrobbles)
    logger.info(f"Created {len(created)} weigh-in scrobbles")
    for scrobble in created:
        ScrobbleNtfyNotification(scrobble).send()
    return created
