"""
Unit tests for unite.py
-----------------------

- These tests are based on splitting a field in different ways and putting it back together with unite.
- Fields passed to unite must fulfill a set of basic requirements, which are also tested.
- Optional checks on the fields are not tested here because they have their own dedicated tests.
"""

import pytest
import pandas as pd
from canopy.tests.test_data.registry import load_test_data
from canopy.util.unite import unite
from canopy.core.grid import GridLonLat
from canopy.core.field import Field


def test_disjoint():
    """Uniting three spatial pieces"""

    field = load_test_data('anpp_spain_1990_2010.out.gz')

    f1, f2, f3 = field.select_slice({'lon':(-10,-5), 'lat':(35,42)}), \
                 field.select_slice({'lon':(-10,-5), 'lat':(40, 45)}), \
                 field.select_slice({'lon':(-5, 4)})

    field_united = unite([f1, f2, f3])

    assert field.data.equals(field_united.data)


def test_overlapping():
    """Uniting two fully overlapping spatial pieces"""

    field = load_test_data('anpp_spain_1990_2010.out.gz')

    field_united = unite([field, field])

    assert field.data.equals(field_united.data)


def test_disjoint_time():
    """Unite three time series"""

    field = load_test_data('anpp_spain_1990_2010.out.gz')

    f1, f2, f3 = (field.select_slice({'time':(x,y)}) for x, y in [(1990,2000), (2000,2004), (2004,2010)])

    field_united = unite([f1, f2, f3])

    assert field_united.data.equals(field.data)


def test_overlapping_layers():
    """Returned field has only overlapping layers from the pieces."""

    field = load_test_data('anpp_spain_1990_2010.out.gz')

    f1 = field[['Abi_alb', 'BES', 'Fag_syl']].select_slice({'lon':(-10,-5)})
    f2 = field[['BES', 'Fag_syl', 'C3_gr']].select_slice({'lon':(-5,5)})
    f12 = unite([f1, f2])

    assert field[['BES', 'Fag_syl']].data.equals(f12.data)


def test_reduced_lat():

    field = load_test_data('anpp_spain_1990_2010.out.gz')

    f1, f2 = field.select_slice({'lon':(-10,-5)}).reduce_grid('av', 'lat'), \
             field.select_slice({'lon':(-5, 4)}).reduce_grid('av', 'lat')

    field_united = unite([f1, f2])

    assert field.reduce_grid('av', 'lat').data.equals(field_united.data)


def test_reduced_lon():

    field = load_test_data('anpp_spain_1990_2010.out.gz')

    f1, f2 = field.select_slice({'lat':(35,40)}).reduce_grid('av', 'lon'), \
             field.select_slice({'lat':(40,45)}).reduce_grid('av', 'lon')

    field_united = unite([f1, f2])

    assert field.reduce_grid('av', 'lon').data.equals(field_united.data)


def test_reduced_grid():

    field = load_test_data('anpp_spain_1990_2010.out.gz').reduce_grid('av')
    f1, f2, f3 = (field.select_slice({'time':(x,y)}) for x, y in [(1990,2000), (2000,2004), (2004,2010)])

    field_united = unite([f1, f2, f3])

    assert field.data.equals(field_united.data)


def test_different_frequencies():
    """Returned field has only overlapping layers from the pieces."""

    field_1Y = load_test_data('anpp_spain_1990_2010.out.gz')
    field_5Y = field_1Y.reduce_time('av', '5Y')

    with pytest.raises(ValueError, match="All fields must have the same time frequency.") as v_error:
        unite([field_1Y, field_5Y])


def test_different_grid_types():

    field_sites = load_test_data('aaet_global_sites.out.gz')
    field_lonlat = load_test_data('anpp_spain_1990_2010.out.gz')

    with pytest.raises(ValueError, match="Field grids must all be of the same type.") as v_error:
        unite([field_sites, field_lonlat])


def test_incompatible_grid_types():

    field1 = load_test_data('anpp_spain_1990_2010.out.gz')

    df = field1.data.reset_index()
    df['lon'] += 0.1
    df = df.set_index(['lon', 'lat', 'time'])
    grid = GridLonLat.from_frame(df)
    field2 = Field(df, grid)

    df = field2.data.reset_index()
    df['lat'] += 0.1
    df = df.set_index(['lon', 'lat', 'time'])
    grid = GridLonLat.from_frame(df)
    field3 = Field(df, grid)

    with pytest.raises(ValueError, match="Field grids must all be mutually compatible.") as v_error:
        unite([field1, field1, field2, field3])
