from pathlib import Path

import pytest

import numpy as np

import framel

#: directory containing test data files
DATA_PATH = Path(__file__).parent / "data"

#: list of 'testStat' GWF files
STAT_DATA_FILES = [
    pytest.param(x, id=x.name)
    for x in DATA_PATH.glob("testStat*.gwf")
]

DATA_TYPES = {
    "INT16": np.int16,
    "INT32": np.int32,
    "INT64": np.int64,
    "UINT8": np.uint8,
    "UINT16": np.uint16,
    "UINT32": np.uint32,
    "UINT64": np.uint64,
    "FLOAT32": np.float32,
    "FLOAT64": np.float64,
    "COMPLEX64": np.complex64,
    "COMPLEX128": np.complex128,
}
FRDATA_TYPE = ["PROC", "ADC", "SIM"]
NUM_CHANNEL_TYPE = 7  # see GWF spec 4.3.2.11
NUM_CHANNEL_SUBTYPE = 7  # see GWF spec 4.3.2.11
CHANNELNAME = "V1:test_channel"
START = 1234567890
DX = 1.e6
X_UNIT = "sec"
Y_UNIT = "Hz"


@pytest.fixture(scope="module")
def datafile(tmp_path_factory):
    """Create a GWF file with lots of data in it.

    The `scope="module"` means that this file is created once for all tests
    to use, and should contain one channel for each numpy type, iterating
    over the various permutations of frdata type, channel type, and channel
    subtype.
    """
    # create temporary directory for these data
    tmpdir = tmp_path_factory.mktemp("data")
    gwf = str(tmpdir / "test.gwf")

    data = np.arange(100000)

    # Setup the channellist, testing all datatypes and options
    channels = []
    for i, dtype in enumerate(DATA_TYPES):
        channels.append({
            "name":    f"{CHANNELNAME}_{dtype}",
            "data":    data.astype(DATA_TYPES[dtype]),
            "start":   START,
            "dx":      DX,
            "x_unit":  X_UNIT,
            "y_unit":  Y_UNIT,
            "kind":    FRDATA_TYPE[i % len(FRDATA_TYPE)],
            "type":    i % NUM_CHANNEL_TYPE,
            "subType": i % NUM_CHANNEL_SUBTYPE,
            "history": "Test string",
            "verbose": True,
        })

    framel.frputvect(gwf, channels)
    return gwf


# test is redundant with datafile fixture above
#def test_frputvect():
#    pass


@pytest.mark.parametrize("dtype", DATA_TYPES)
def test_frgetvect(datafile, dtype):
    """Test that `frgetvect1d` can read a channel from a GWF file.
    """
    # read the data
    data, start, startX, dx, unitX, unitY = framel.frgetvect1d(
        datafile,
        f"{CHANNELNAME}_{dtype}",
        verbose=True,
    )

    # assert that we get what we should
    assert data.dtype.type is DATA_TYPES[dtype]
    assert start == START
    assert dx == DX
    assert unitX == X_UNIT
    assert unitY == Y_UNIT


@pytest.mark.parametrize("gwf", STAT_DATA_FILES)
def test_frgetvect_stat(gwf):
    """Test that `frgetvect1d` can read the test data files.
    """
    data, start, startX, dx, unitX, unitY = framel.frgetvect1d(
        str(gwf),
        f"gain",
        start=1000000010,
        verbose=True,
    )
    assert start == 0
    assert startX == 0
    assert dx == 1.0
    assert unitX == "relatif_gain"
    assert unitY == ""


def test_frgetevent():
    """Test that `frgetevent()` can read data.
    """
    events = framel.frgetevent(str(DATA_PATH / "testEvent.gwf"), verbose=True)
    assert len(events) == 48
    e = events[0]
    assert e["GTimeS"] == 728729563
    assert e["GTimeN"] == 509340882
    assert e["amplitude"] == 4.660720403979051e-20
