import json

import pytest
import yaml

from gallery.utils import metadata


def test_load_metadata_file_yaml(tmp_path):
    data = {"a": 1, "b": "test"}
    yaml_path = tmp_path / "meta.yaml"
    yaml_path.write_text(yaml.dump(data))
    result = metadata.load_metadata_file(yaml_path)
    assert result == data


def test_load_metadata_file_json(tmp_path):
    data = {"x": 42, "y": "hello"}
    json_path = tmp_path / "meta.json"
    json_path.write_text(json.dumps(data))
    result = metadata.load_metadata_file(json_path)
    assert result == data


def test_load_metadata_file_missing(tmp_path):
    missing_path = tmp_path / "nope.yaml"
    result = metadata.load_metadata_file(missing_path)
    assert result == {}


def test_load_metadata_file_yml_extension(tmp_path):
    data = {"test": "yml_format"}
    yml_path = tmp_path / "meta.yml"
    yml_path.write_text(yaml.dump(data))
    result = metadata.load_metadata_file(yml_path)
    assert result == data


def test_load_metadata_file_unknown_format(tmp_path):
    txt_path = tmp_path / "meta.txt"
    txt_path.write_text("some text")
    result = metadata.load_metadata_file(txt_path)
    assert result == {}


def test_load_metadata_file_malformed_yaml(tmp_path):
    yaml_path = tmp_path / "bad.yaml"
    yaml_path.write_text("invalid: yaml: content: [")
    with pytest.raises(yaml.YAMLError):
        metadata.load_metadata_file(yaml_path)


def test_load_metadata_file_malformed_json(tmp_path):
    json_path = tmp_path / "bad.json"
    json_path.write_text('{"invalid": json}')
    with pytest.raises(json.JSONDecodeError):
        metadata.load_metadata_file(json_path)


def test_load_folder_metadata_yaml(tmp_path):
    data = {"folder": "metadata"}
    metadata_path = tmp_path / "metadata.yaml"
    metadata_path.write_text(yaml.dump(data))
    result = metadata.load_folder_metadata(tmp_path)
    assert result == data


def test_load_folder_metadata_yml(tmp_path):
    data = {"folder": "metadata_yml"}
    metadata_path = tmp_path / "metadata.yml"
    metadata_path.write_text(yaml.dump(data))
    result = metadata.load_folder_metadata(tmp_path)
    assert result == data


def test_load_folder_metadata_json(tmp_path):
    data = {"folder": "metadata_json"}
    metadata_path = tmp_path / "metadata.json"
    metadata_path.write_text(json.dumps(data))
    result = metadata.load_folder_metadata(tmp_path)
    assert result == data


def test_load_folder_metadata_missing(tmp_path):
    result = metadata.load_folder_metadata(tmp_path)
    assert result == {}


def test_get_metadata_file_path_existing_yaml(tmp_path):
    metadata_path = tmp_path / "metadata.yaml"
    metadata_path.write_text("test: data")
    result = metadata.get_metadata_file_path(tmp_path)
    assert result == str(metadata_path)


def test_get_metadata_file_path_existing_yml(tmp_path):
    metadata_path = tmp_path / "metadata.yml"
    metadata_path.write_text("test: data")
    result = metadata.get_metadata_file_path(tmp_path)
    assert result == str(metadata_path)


def test_get_metadata_file_path_existing_json(tmp_path):
    metadata_path = tmp_path / "metadata.json"
    metadata_path.write_text('{"test": "data"}')
    result = metadata.get_metadata_file_path(tmp_path)
    assert result == str(metadata_path)


def test_get_metadata_file_path_none_existing(tmp_path):
    result = metadata.get_metadata_file_path(tmp_path)
    expected = str(tmp_path / "metadata.yaml")
    assert result == expected


def test_merge_metadata():
    parent = {"project": "Test", "version": "1.0", "author": "Parent"}
    child = {"experiment": "A", "version": "1.1"}
    merged = metadata.merge_metadata(parent, child)
    expected = {"project": "Test", "version": "1.1", "author": "Parent", "experiment": "A"}
    assert merged == expected


def test_merge_metadata_empty_parent():
    parent = {}
    child = {"experiment": "A", "version": "1.1"}
    merged = metadata.merge_metadata(parent, child)
    assert merged == child


def test_merge_metadata_empty_child():
    parent = {"project": "Test", "version": "1.0"}
    child = {}
    merged = metadata.merge_metadata(parent, child)
    assert merged == parent


def test_resolve_metadata_for_plot_with_specific_yaml(tmp_path):
    # Create plot-specific metadata file
    plot_path = tmp_path / "test_plot.pdf"
    plot_metadata_path = tmp_path / "test_plot.yaml"
    plot_metadata = {"specific": "plot_data", "override": "plot_value"}
    plot_metadata_path.write_text(yaml.dump(plot_metadata))

    inherited = {"general": "data", "override": "inherited_value"}
    result = metadata.resolve_metadata_for_plot(plot_path, inherited)

    expected = {"general": "data", "override": "plot_value", "specific": "plot_data"}
    assert result == expected


def test_resolve_metadata_for_plot_with_specific_json(tmp_path):
    plot_path = tmp_path / "test_plot.pdf"
    plot_metadata_path = tmp_path / "test_plot.json"
    plot_metadata = {"specific": "plot_data_json"}
    plot_metadata_path.write_text(json.dumps(plot_metadata))

    inherited = {"general": "data"}
    result = metadata.resolve_metadata_for_plot(plot_path, inherited)

    expected = {"general": "data", "specific": "plot_data_json"}
    assert result == expected


def test_resolve_metadata_for_plot_no_specific(tmp_path):
    plot_path = tmp_path / "test_plot.pdf"
    inherited = {"general": "data", "inherited": "value"}
    result = metadata.resolve_metadata_for_plot(plot_path, inherited)

    # Should return copy of inherited metadata
    assert result == inherited
    assert result is not inherited  # Should be a copy


def test_save_metadata_cache(tmp_path):
    cache_data = {"plot1": {"title": "Plot 1", "author": "Test"}, "plot2": {"title": "Plot 2", "experiment": "B"}}

    metadata.save_metadata_cache(tmp_path, cache_data)

    cache_file = tmp_path / "meta_cache.json"
    assert cache_file.exists()

    with cache_file.open("r") as f:
        loaded_data = json.load(f)

    assert loaded_data == cache_data


def test_save_metadata_cache_empty(tmp_path):
    cache_data = {}
    metadata.save_metadata_cache(tmp_path, cache_data)

    cache_file = tmp_path / "meta_cache.json"
    assert cache_file.exists()

    with cache_file.open("r") as f:
        loaded_data = json.load(f)

    assert loaded_data == {}
