"""Core conversion logic for CED .cfs files."""

import json
import os

import biosig
import numpy as np
from scipy.io import savemat


def read_cfs(cfs_path):
    """Read a CED .cfs file and return header dict and data array.

    Returns:
        tuple: (header_dict, data_array) where data is (samples, channels).
    """
    hdr = json.loads(biosig.header(cfs_path))
    data = biosig.data(cfs_path)
    return hdr, data


def cfs_to_mat(cfs_path, mat_path=None, flat=False):
    """Convert a CED .cfs file to MATLAB .mat format.

    Args:
        cfs_path: Path to the input .cfs file.
        mat_path: Path for the output .mat file. Defaults to same name with .mat extension.
        flat: If True, store data as flat (samples x channels) only, skip sweep reshape.

    Returns:
        Path to the saved .mat file.
    """
    if mat_path is None:
        mat_path = os.path.splitext(cfs_path)[0] + ".mat"

    hdr, data = read_cfs(cfs_path)

    n_sweeps = hdr.get("NumberOfSweeps", 1)
    channels = hdr.get("CHANNEL", [])
    channel_labels = [ch["Label"] for ch in channels]
    channel_units = [ch["PhysicalUnit"] for ch in channels]
    channel_sampling_rates = [ch["Samplingrate"] for ch in channels]

    events = hdr.get("EVENT", [])

    mat_dict = {
        "data_flat": data,
        # File-level metadata
        "file_type": hdr.get("TYPE", ""),
        "file_version": hdr.get("VERSION", 0),
        "filename": hdr.get("Filename", ""),
        "n_channels": np.int32(hdr.get("NumberOfChannels", 0)),
        "n_records": np.int32(hdr.get("NumberOfRecords", 0)),
        "n_samples": np.int32(hdr.get("NumberOfSamples", 0)),
        "n_sweeps": np.int32(n_sweeps),
        "sampling_rate": hdr.get("Samplingrate", 0),
        "start_of_recording": hdr.get("StartOfRecording", ""),
        "timezone_minutes_east_utc": np.int32(hdr.get("TimezoneMinutesEastOfUTC", 0)),
        # Patient
        "patient_id": hdr.get("Patient", {}).get("Id", ""),
        "patient_gender": hdr.get("Patient", {}).get("Gender", ""),
        # Manufacturer
        "manufacturer": hdr.get("Manufacturer", {}).get("Name", ""),
        # Channel metadata
        "channel_labels": np.array(channel_labels, dtype=object),
        "channel_units": np.array(channel_units, dtype=object),
        "channel_sampling_rates": np.array(channel_sampling_rates),
        "channel_scaling": np.array([ch.get("scaling", 1) for ch in channels]),
        "channel_offset": np.array([ch.get("offset", 0) for ch in channels]),
        "channel_physical_max": np.array([ch.get("PhysicalMaximum", 0) for ch in channels]),
        "channel_physical_min": np.array([ch.get("PhysicalMinimum", 0) for ch in channels]),
        "channel_digital_max": np.array([ch.get("DigitalMaximum", 0) for ch in channels]),
        "channel_digital_min": np.array([ch.get("DigitalMinimum", 0) for ch in channels]),
        # Events
        "event_types": np.array([e.get("TYP", "") for e in events], dtype=object),
        "event_positions": np.array([e.get("POS", 0) for e in events]),
        "event_timestamps": np.array([e.get("TimeStamp", "") for e in events], dtype=object),
        "event_descriptions": np.array([e.get("Description", "") for e in events], dtype=object),
        # Full header as JSON string
        "header_json": json.dumps(hdr, default=str),
    }

    # Reshape into sweeps if possible
    if not flat and n_sweeps > 1 and data.shape[0] % n_sweeps == 0:
        samples_per_sweep = data.shape[0] // n_sweeps
        mat_dict["data"] = data.reshape(n_sweeps, samples_per_sweep, data.shape[1])
        mat_dict["samples_per_sweep"] = np.int32(samples_per_sweep)

    savemat(mat_path, mat_dict, do_compression=True)
    return mat_path
