"""Tests for Kaggle data path resolution and HDF5-backed Glottis dataset."""

from __future__ import annotations

import os
from pathlib import Path

import numpy as np
import pytest

import cv2


def test_is_kaggle_false_by_default() -> None:
    """When KAGGLE_KERNEL_RUN_TYPE is unset, is_kaggle() is False."""
    from openglottal.kaggle_paths import is_kaggle

    with pytest.MonkeyPatch.context() as m:
        m.delenv("KAGGLE_KERNEL_RUN_TYPE", raising=False)
        assert is_kaggle() is False


def test_is_kaggle_true_when_env_set() -> None:
    """When KAGGLE_KERNEL_RUN_TYPE is set, is_kaggle() is True."""
    from openglottal.kaggle_paths import is_kaggle

    with pytest.MonkeyPatch.context() as m:
        m.setenv("KAGGLE_KERNEL_RUN_TYPE", "Interactive")
        assert is_kaggle() is True


def test_get_kaggle_bagls_path_returns_none_when_not_on_kaggle() -> None:
    """get_kaggle_bagls_path returns None when not running on Kaggle."""
    from openglottal.kaggle_paths import get_kaggle_bagls_path

    with pytest.MonkeyPatch.context() as m:
        m.delenv("KAGGLE_KERNEL_RUN_TYPE", raising=False)
    assert get_kaggle_bagls_path("training") is None
    assert get_kaggle_bagls_path("test") is None


def test_resolve_kaggle_data_paths_returns_none_for_non_bagls() -> None:
    """resolve_kaggle_data_paths returns None for unsupported dataset."""
    from openglottal.data import resolve_kaggle_data_paths

    assert resolve_kaggle_data_paths("girafe", "training") is None
    assert resolve_kaggle_data_paths("other", "test") is None


def test_resolve_kaggle_data_paths_returns_none_when_not_on_kaggle() -> None:
    """resolve_kaggle_data_paths returns None when not on Kaggle (BAGLS)."""
    from openglottal.data import resolve_kaggle_data_paths

    with pytest.MonkeyPatch.context() as m:
        m.delenv("KAGGLE_KERNEL_RUN_TYPE", raising=False)
    assert resolve_kaggle_data_paths("bagls", "training") is None


def test_resolve_kaggle_data_paths_returns_same_dir_for_bagls_when_on_kaggle(
    tmp_path: Path,
) -> None:
    """When on Kaggle and BAGLS path exists, resolve returns (path, path)."""
    from openglottal.kaggle_paths import KAGGLE_BAGLS_SLUG

    # Simulate Kaggle: KAGGLE_INPUT / BAGLS_SLUG / "training"
    kaggle_input = tmp_path / "kaggle_input"
    bagls_training = kaggle_input / KAGGLE_BAGLS_SLUG / "training"
    bagls_training.mkdir(parents=True)
    (kaggle_input / KAGGLE_BAGLS_SLUG / "test").mkdir(parents=True)

    with pytest.MonkeyPatch.context() as m:
        m.setenv("KAGGLE_KERNEL_RUN_TYPE", "Interactive")
        import openglottal.kaggle_paths as kp

        m.setattr(kp, "KAGGLE_INPUT", kaggle_input)
        from openglottal.data import resolve_kaggle_data_paths

        result = resolve_kaggle_data_paths("bagls", "training")
        assert result is not None
        img_dir, lbl_dir = result
        assert img_dir == lbl_dir
        assert img_dir == bagls_training
        assert img_dir.is_dir()


def test_build_glottis_hdf5_and_load(tmp_path: Path) -> None:
    """Build HDF5 from small fake PNGs and load via GlottisDatasetHDF5."""
    from openglottal.data import GlottisDatasetHDF5, build_glottis_hdf5

    img_dir = tmp_path / "images"
    lbl_dir = tmp_path / "labels"
    img_dir.mkdir()
    lbl_dir.mkdir()

    size = 64  # small for test
    fnames = ["a.png", "b.png"]
    for i, fname in enumerate(fnames):
        stem = Path(fname).stem
        img = np.full((size, size), 100 + i * 50, dtype=np.uint8)
        msk = np.zeros((size, size), dtype=np.uint8)
        msk[16:48, 16:48] = 255
        cv2.imwrite(str(img_dir / fname), img)
        cv2.imwrite(str(lbl_dir / f"{stem}_seg.png"), msk)

    out_h5 = tmp_path / "cache.h5"
    build_glottis_hdf5(
        fnames,
        img_dir,
        lbl_dir,
        out_h5,
        label_suffix="_seg",
        size=256,
    )
    assert out_h5.exists()

    ds = GlottisDatasetHDF5(out_h5, augment=False)
    assert len(ds) == 2
    img, msk = ds[0]
    assert img.shape == (1, 256, 256)
    assert msk.shape == (1, 256, 256)
    assert 0 <= img.min() <= img.max() <= 1.0
    assert msk.min() in (0.0, 1.0) and msk.max() in (0.0, 1.0)

    img1, msk1 = ds[1]
    assert img1.shape == (1, 256, 256)
    assert msk1.shape == (1, 256, 256)


def test_glottis_dataset_hdf5_augment_true(tmp_path: Path) -> None:
    """GlottisDatasetHDF5 with augment=True returns valid tensors."""
    from openglottal.data import GlottisDatasetHDF5, build_glottis_hdf5

    img_dir = tmp_path / "im"
    lbl_dir = tmp_path / "lb"
    img_dir.mkdir()
    lbl_dir.mkdir()
    cv2.imwrite(str(img_dir / "x.png"), np.zeros((64, 64), dtype=np.uint8))
    cv2.imwrite(str(lbl_dir / "x_seg.png"), np.ones((64, 64), dtype=np.uint8) * 255)

    h5_path = tmp_path / "tiny.h5"
    build_glottis_hdf5(["x.png"], img_dir, lbl_dir, h5_path, label_suffix="_seg", size=256)

    ds = GlottisDatasetHDF5(h5_path, augment=True)
    img, msk = ds[0]
    assert img.shape == (1, 256, 256)
    assert msk.shape == (1, 256, 256)
    assert float(img.min()) >= 0 and float(img.max()) <= 1.5  # contrast can push slightly >1
