"""Unit tests for Maxwell potential assemblers."""

# pylint: disable=redefined-outer-name
# pylint: disable=C0103

import numpy as _np
import pytest

pytestmark = pytest.mark.usefixtures("default_parameters", "helpers")

WAVENUMBER = 2.5
WAVENUMBER_COMPLEX = 2.5 + 1j


def test_maxwell_electric_field_potential_complex(
    default_parameters, helpers, device_interface, precision
):
    """Test Maxwell efield potential with complex wavenumber."""
    from bempp.api import function_space
    from bempp.api import GridFunction
    from bempp.api.operators.potential.maxwell import electric_field

    grid = helpers.load_grid("sphere")
    space = function_space(grid, "RWG", 0)

    data = helpers.load_npz_data("maxwell_electric_field_potential_complex")

    coefficients = data["vec"]
    points = data["points"]
    expected = data["result"]

    fun = GridFunction(space, coefficients=coefficients)

    actual = electric_field(
        space,
        points,
        WAVENUMBER_COMPLEX,
        parameters=default_parameters,
        precision=precision,
        device_interface=device_interface,
    ).evaluate(fun)

    _np.testing.assert_allclose(actual, expected, rtol=helpers.default_tolerance(precision))


def test_maxwell_electric_field_potential_rwg(
    default_parameters, helpers, device_interface, precision
):
    """Test Maxwell efield potential."""
    from bempp.api import function_space
    from bempp.api import GridFunction
    from bempp.api.operators.potential.maxwell import electric_field

    grid = helpers.load_grid("sphere")
    space = function_space(grid, "RWG", 0)

    data = helpers.load_npz_data("maxwell_electric_field_potential")

    coefficients = data["vec"]
    points = data["points"]
    expected = data["result"]

    fun = GridFunction(space, coefficients=coefficients)

    actual = electric_field(
        space,
        points,
        WAVENUMBER,
        parameters=default_parameters,
        precision=precision,
        device_interface=device_interface,
    ).evaluate(fun)

    _np.testing.assert_allclose(actual, expected, rtol=helpers.default_tolerance(precision))


def test_maxwell_electric_field_potential_bc(
    default_parameters, helpers, device_interface, precision
):
    """Test Maxwell efield potential."""
    from bempp.api import function_space
    from bempp.api import GridFunction
    from bempp.api.operators.potential.maxwell import electric_field

    grid = helpers.load_grid("sphere")
    space = function_space(grid, "BC", 0)

    data = helpers.load_npz_data("maxwell_electric_field_potential_bc")

    coefficients = data["vec"]
    points = data["points"]
    expected = data["result"]

    fun = GridFunction(space, coefficients=coefficients)

    actual = electric_field(
        space,
        points,
        WAVENUMBER,
        parameters=default_parameters,
        precision=precision,
        device_interface=device_interface,
    ).evaluate(fun)

    _np.testing.assert_allclose(actual, expected, rtol=helpers.default_tolerance(precision))

def test_maxwell_magnetic_field_potential_rwg(
    default_parameters, helpers, device_interface, precision
):
    """Test Maxwell magnetic potential."""
    from bempp.api import function_space
    from bempp.api import GridFunction
    from bempp.api.operators.potential.maxwell import magnetic_field

    grid = helpers.load_grid("sphere")
    space = function_space(grid, "RWG", 0)

    data = helpers.load_npz_data("maxwell_magnetic_field_potential")

    coefficients = data["vec"]
    points = data["points"]
    expected = data["result"]

    fun = GridFunction(space, coefficients=coefficients)

    actual = magnetic_field(
        space,
        points,
        WAVENUMBER,
        parameters=default_parameters,
        precision=precision,
        device_interface=device_interface,
    ).evaluate(fun)

    _np.testing.assert_allclose(actual, expected, rtol=helpers.default_tolerance(precision))


def test_maxwell_magnetic_field_potential_complex(
    default_parameters, helpers, device_interface, precision
):
    """Test Maxwell magnetic potential with complex wavenumber."""
    from bempp.api import function_space
    from bempp.api import GridFunction
    from bempp.api.operators.potential.maxwell import magnetic_field

    grid = helpers.load_grid("sphere")
    space = function_space(grid, "RWG", 0)

    data = helpers.load_npz_data("maxwell_magnetic_field_potential_complex")

    coefficients = data["vec"]
    points = data["points"]
    expected = data["result"]

    fun = GridFunction(space, coefficients=coefficients)

    actual = magnetic_field(
        space,
        points,
        WAVENUMBER_COMPLEX,
        parameters=default_parameters,
        precision=precision,
        device_interface=device_interface,
    ).evaluate(fun)

    _np.testing.assert_allclose(actual, expected, rtol=helpers.default_tolerance(precision))

def test_maxwell_potentials_segments(
        default_parameters, helpers, device_interface, precision):
    """Test Maxwell potentials on segments."""
    import bempp.api
    from bempp.api import function_space
    from bempp.api import GridFunction
    from bempp.api.operators.potential.maxwell import electric_field
    from bempp.api.operators.potential.maxwell import magnetic_field
    from bempp.api.grid.grid import grid_from_segments

    grid = bempp.api.shapes.multitrace_cube()

    seglists = [[1, 2, 3, 4, 5, 6], [6, 7, 8, 9, 10, 11]]
    swapped_normal_lists = [{}, {6}]

    rand = _np.random.RandomState(0)

    for op in [electric_field, magnetic_field]:
        for seglist, swapped_normals in zip(seglists, swapped_normal_lists):
            new_grid = grid_from_segments(grid, seglist)

            coeffs = rand.rand(new_grid.number_of_edges)
            
            space1 = function_space(grid, "RWG", 0, segments=seglist, swapped_normals=swapped_normals,
                include_boundary_dofs=True)
            space2 = function_space(new_grid, "RWG", 0, swapped_normals=swapped_normals)

            points = _np.array([2.3, 1.3, 1.5]).reshape(3, 1) + rand.rand(3, 5)
            fun1 = bempp.api.GridFunction(space1, coefficients=coeffs)
            fun2 = bempp.api.GridFunction(space2, coefficients=coeffs)

            actual = op(space1, points, 2.5) * fun1
            expected = op(space2, points, 2.5) * fun2

            _np.testing.assert_allclose(
                actual, expected, rtol=helpers.default_tolerance(precision)
            )

def test_maxwell_potentials_segments_complex_coeffs(
        default_parameters, helpers, device_interface, precision):
    """Test Maxwell potentials on segments with complex coeffs."""
    import bempp.api
    from bempp.api import function_space
    from bempp.api import GridFunction
    from bempp.api.operators.potential.maxwell import electric_field
    from bempp.api.operators.potential.maxwell import magnetic_field
    from bempp.api.grid.grid import grid_from_segments

    grid = bempp.api.shapes.multitrace_cube()

    seglists = [[1, 2, 3, 4, 5, 6], [6, 7, 8, 9, 10, 11]]
    swapped_normal_lists = [{}, {6}]

    rand = _np.random.RandomState(0)

    for op in [electric_field, magnetic_field]:
        for seglist, swapped_normals in zip(seglists, swapped_normal_lists):
            new_grid = grid_from_segments(grid, seglist)

            coeffs = rand.rand(new_grid.number_of_edges) + 1j * rand.rand(new_grid.number_of_edges)
            
            space1 = function_space(grid, "RWG", 0, segments=seglist, swapped_normals=swapped_normals,
                include_boundary_dofs=True)
            space2 = function_space(new_grid, "RWG", 0, swapped_normals=swapped_normals)

            points = _np.array([2.3, 1.3, 1.5]).reshape(3, 1) + rand.rand(3, 5)
            fun1 = bempp.api.GridFunction(space1, coefficients=coeffs)
            fun2 = bempp.api.GridFunction(space2, coefficients=coeffs)

            actual = op(space1, points, 2.5) * fun1
            expected = op(space2, points, 2.5) * fun2

            _np.testing.assert_allclose(
                actual, expected, rtol=helpers.default_tolerance(precision)
            )
