"""DatasetMetadata <-> proto converters."""

from __future__ import annotations

from typing import TYPE_CHECKING

from radiens_core._converters._channels import channel_metadata_from_proto
from radiens_core._generated import common_pb2
from radiens_core.models.dataset import DatasetMetadata, RadiensFileType
from radiens_core.models.time_range import TimeRange

if TYPE_CHECKING:
    from radiens_core._generated import datasource_pb2


# --- RadiensFileType enum conversion ---

_FILE_TYPE_FROM_PROTO: dict[int, RadiensFileType] = {
    int(common_pb2.RHD): RadiensFileType.RHD,
    int(common_pb2.XDAT): RadiensFileType.XDAT,
    int(common_pb2.CSV): RadiensFileType.CSV,
    int(common_pb2.HDF5): RadiensFileType.HDF5,
    int(common_pb2.NEX5): RadiensFileType.NEX5,
    int(common_pb2.NWB): RadiensFileType.NWB,
    int(common_pb2.KILOSORT2): RadiensFileType.KILOSORT2,
    int(common_pb2.NSX): RadiensFileType.NSX,
    int(common_pb2.TDT): RadiensFileType.TDT,
    int(common_pb2.SPIKES): RadiensFileType.SPIKES,
    int(common_pb2.OE_DAT): RadiensFileType.OE_DAT,
}

_FILE_TYPE_TO_PROTO: dict[RadiensFileType, common_pb2.RadixFileTypes.ValueType] = {
    RadiensFileType.RHD: common_pb2.RHD,
    RadiensFileType.XDAT: common_pb2.XDAT,
    RadiensFileType.CSV: common_pb2.CSV,
    RadiensFileType.HDF5: common_pb2.HDF5,
    RadiensFileType.NEX5: common_pb2.NEX5,
    RadiensFileType.NWB: common_pb2.NWB,
    RadiensFileType.KILOSORT2: common_pb2.KILOSORT2,
    RadiensFileType.NSX: common_pb2.NSX,
    RadiensFileType.TDT: common_pb2.TDT,
    RadiensFileType.SPIKES: common_pb2.SPIKES,
    RadiensFileType.OE_DAT: common_pb2.OE_DAT,
}


def file_type_from_proto(pb: int) -> RadiensFileType:
    """Convert proto RadixFileTypes int to domain RadiensFileType."""
    return _FILE_TYPE_FROM_PROTO[pb]


def file_type_to_proto(ft: RadiensFileType) -> common_pb2.RadixFileTypes.ValueType:
    """Convert domain RadiensFileType to proto RadixFileTypes."""
    return _FILE_TYPE_TO_PROTO[ft]


def guess_file_type(path: str) -> RadiensFileType:
    """Guess file type from file extension."""
    ext = path.rsplit(".", maxsplit=1)[-1].lower() if "." in path else ""
    ext_map: dict[str, RadiensFileType] = {
        "xdat": RadiensFileType.XDAT,
        "rhd": RadiensFileType.RHD,
        "csv": RadiensFileType.CSV,
        "hdf5": RadiensFileType.HDF5,
        "h5": RadiensFileType.HDF5,
        "nex5": RadiensFileType.NEX5,
        "nwb": RadiensFileType.NWB,
        "bin": RadiensFileType.KILOSORT2,
        "nsx": RadiensFileType.NSX,
        "tdt": RadiensFileType.TDT,
        "oebin": RadiensFileType.OE_DAT,
    }
    return ext_map.get(ext, RadiensFileType.XDAT)


def dataset_metadata_from_proto(
    raw: datasource_pb2.DataSourceSetSaveReply,
) -> DatasetMetadata:
    """Build domain DatasetMetadata from proto DataSourceSetSaveReply."""
    status = raw.status
    sig_group = status.signalGroup
    pb_tr = status.tR

    channel_metadata = channel_metadata_from_proto(sig_group)

    # Build TimeRange from the proto TimeRange message
    sec_list = list(pb_tr.timeRangeSec)
    ts_list = list(pb_tr.timestamp)
    sec_start = sec_list[0] if len(sec_list) > 0 else 0.0
    sec_end = sec_list[1] if len(sec_list) > 1 else 0.0
    ts_start = ts_list[0] if len(ts_list) > 0 else 0
    ts_end = ts_list[1] if len(ts_list) > 1 else 0

    time_range = TimeRange(
        sec=(sec_start, sec_end),
        timestamp=(ts_start, ts_end),
        fs=pb_tr.fs,
        dur_sec=sec_end - sec_start,
        walltime_str=pb_tr.wallTimeStart,
        n=ts_end - ts_start,
    )

    return DatasetMetadata(
        id=raw.dsourceID,
        base_name=status.baseFileName,
        path=status.path,
        file_type=file_type_from_proto(status.fileType),
        time_range=time_range,
        channel_metadata=channel_metadata,
        parent_dsource_id="",
        probe_uid=sig_group.datasetUID,
    )
