import unittest

from osaft import WaveType, doinikov1994compressible, yosioka1955
from osaft.core.basecomposite import (
    BaseFrequencyComposite,
    BaseSphereFrequencyComposite,
)
from osaft.core.frequency import Frequency
from osaft.core.functions import pi
from osaft.core.geometries import Sphere
from osaft.core.solids import ElasticSolid
from osaft.tests.basetest_numeric import BaseTestSolutions


class TestBaseFrequencyComposite(BaseTestSolutions):
    def test_types_for_frequency(self):
        cls = BaseFrequencyComposite(10.1)
        self.assertTrue(isinstance(cls, BaseFrequencyComposite))
        cls = BaseFrequencyComposite(10.1)
        self.assertTrue(isinstance(cls, BaseFrequencyComposite))

        F = Frequency(1e6)
        cls = BaseFrequencyComposite(F)
        self.assertTrue(isinstance(cls, BaseFrequencyComposite))

    def test_TypeError(self):

        self.assertRaises(TypeError, BaseFrequencyComposite, "s")

    def test_input_variables(self):

        # Test elastic solid
        solid = ElasticSolid(1e6, 1e6, 0.3, 1e3)
        expected_solid = {"E_s", "nu_s", "rho_s", "f"}
        got_solid = set(solid.input_variables())
        self.assertSetEqual(got_solid, expected_solid)

        # Doinikov Compressible
        doinikov = doinikov1994compressible.ARF(
            1e6,
            1e-6,
            3e3,
            1e3,
            1e-3,
            1e-3,
            1e3,
            1e3,
            1e-3,
            1e-3,
            1e5,
            WaveType.STANDING,
            0,
            True,
        )

        # Test Doinikov 1994 Compressible
        expected_doinikov = {
            "small_boundary_layer",
            "large_boundary_layer",
            "rho_s",
            "c_s",
            "eta_s",
            "zeta_s",
            "position",
            "p_0",
            "wave_type",
            "rho_f",
            "c_f",
            "eta_f",
            "zeta_f",
            "R_0",
            "f",
            "N_max",
            "background_streaming",
        }
        got_doinikov = set(doinikov.input_variables())
        self.assertSetEqual(got_doinikov, expected_doinikov)

        # Test Yosioka & Kawasima (1955)
        yosioka = yosioka1955.ARF(
            1e6,
            1e-6,
            2e3,
            2e3,
            1e3,
            1.5e3,
            1e5,
            WaveType.TRAVELLING,
        )
        expected_yosioka = {
            "small_particle",
            "bubble_solution",
            "position",
            "p_0",
            "wave_type",
            "rho_s",
            "c_s",
            "rho_f",
            "c_f",
            "R_0",
            "f",
            "N_max",
        }
        got_yosioka = set(yosioka.input_variables())
        self.assertSetEqual(got_yosioka, expected_yosioka)


class TestBaseSphereFrequencyComposite(BaseTestSolutions):
    def test_types_for_sphere(self):
        cls = BaseSphereFrequencyComposite(10.1, 10)
        self.assertTrue(isinstance(cls, BaseSphereFrequencyComposite))
        cls = BaseSphereFrequencyComposite(10.1, 10.0)
        self.assertTrue(isinstance(cls, BaseSphereFrequencyComposite))

        S = Sphere(1e-6)
        cls = BaseSphereFrequencyComposite(10.1, S)
        self.assertTrue(isinstance(cls, BaseSphereFrequencyComposite))

    def test_properties(self):
        def V(R):
            return 4 / 3 * R**3 * pi

        def A(R):
            return 4 * R**2 * pi

        R = 1e-6
        f = 1e6
        cls = BaseSphereFrequencyComposite(f, R)

        self.assertAlmostEqual(R, cls.R_0)
        self.assertAlmostEqual(V(R), cls.volume)
        self.assertAlmostEqual(A(R), cls.area)

        R = 4.39e-6
        cls.R_0 = R
        self.assertAlmostEqual(R, cls.R_0)
        self.assertAlmostEqual(V(R), cls.volume)
        self.assertAlmostEqual(A(R), cls.area)

    def test_TypeError(self):
        self.assertRaises(
            TypeError,
            BaseSphereFrequencyComposite,
            10.0,
            "s",
        )


if __name__ == "__main__":
    unittest.main()
