#!/usr/bin/env python3

import argparse
import csv
from datetime import datetime
from pathlib import Path


def load_samples(csv_path: Path):
    rows = []
    source_name = None
    base_time = None
    with csv_path.open("r", encoding="utf-8", newline="") as f:
        reader = csv.DictReader(f)
        fieldnames = reader.fieldnames or []
        if "gyro_z_filtered_pre_bias" in fieldnames:
            source_name = "gyro_z_filtered_pre_bias"
        elif "gyro_raw_z_rad_s" in fieldnames:
            source_name = "gyro_raw_z_rad_s"
        elif "imu_angular_velocity_z" in fieldnames:
            source_name = "imu_angular_velocity_z"
        else:
            raise ValueError("CSV does not contain gyro_z_filtered_pre_bias, gyro_raw_z_rad_s, or imu_angular_velocity_z")
        for row in reader:
            t = row.get("elapsed_s")
            z = row.get(source_name)
            if not z:
                continue
            if t:
                sample_t = float(t)
            else:
                wall_time = row.get("wall_time")
                if not wall_time:
                    continue
                parsed_time = datetime.fromisoformat(wall_time)
                if base_time is None:
                    base_time = parsed_time
                sample_t = (parsed_time - base_time).total_seconds()
            rows.append((sample_t, float(z)))
    return rows, source_name


def fit_line(samples):
    n = len(samples)
    if n < 2:
        raise ValueError("need at least 2 valid samples")

    sum_t = sum(t for t, _ in samples)
    sum_y = sum(y for _, y in samples)
    mean_t = sum_t / n
    mean_y = sum_y / n

    s_tt = sum((t - mean_t) * (t - mean_t) for t, _ in samples)
    if s_tt == 0.0:
        raise ValueError("all timestamps are identical")

    s_ty = sum((t - mean_t) * (y - mean_y) for t, y in samples)
    slope = s_ty / s_tt
    intercept = mean_y - slope * mean_t
    return intercept, slope


def main():
    parser = argparse.ArgumentParser(description="Fit linear gyro z bias from a static feedback CSV")
    parser.add_argument("csv_path", type=Path, help="path to feedback.csv")
    args = parser.parse_args()

    samples, source_name = load_samples(args.csv_path)
    intercept, slope = fit_line(samples)

    print(f"source={source_name}")
    print(f"samples={len(samples)}")
    print(f"gyro_z_bias_intercept={intercept:.12f}")
    print(f"gyro_z_bias_slope={slope:.12f}")
    print(f"bias_model(t)= {intercept:.12f} + {slope:.12f} * t")


if __name__ == "__main__":
    main()
