"""
Tests the Angle string formatting capabilities.  SkyCoord formatting is in
test_sky_coord
"""

import numpy as np
import pytest

from astropy import units as u
from astropy.coordinates import Angle


def test_to_string_precision():
    # There are already some tests in test_api.py, but this is a regression
    # test for the bug in issue #1319 which caused incorrect formatting of the
    # seconds for precision=0

    angle = Angle(-1.23456789, unit=u.degree)

    assert angle.to_string(precision=3) == "-1d14m04.444s"
    assert angle.to_string(precision=1) == "-1d14m04.4s"
    assert angle.to_string(precision=0) == "-1d14m04s"

    angle2 = Angle(-1.23456789, unit=u.hourangle)

    assert angle2.to_string(precision=3, unit=u.hour) == "-1h14m04.444s"
    assert angle2.to_string(precision=1, unit=u.hour) == "-1h14m04.4s"
    assert angle2.to_string(precision=0, unit=u.hour) == "-1h14m04s"

    # Regression test for #7141
    angle3 = Angle(-0.5, unit=u.degree)
    assert angle3.to_string(precision=0, fields=3) == "-0d30m00s"
    assert angle3.to_string(precision=0, fields=2) == "-0d30m"
    assert angle3.to_string(precision=0, fields=1) == "-1d"


def test_to_string_decimal():
    # There are already some tests in test_api.py, but this is a regression
    # test for the bug in issue #1323 which caused decimal formatting to not
    # work

    angle1 = Angle(2.0, unit=u.degree)

    assert angle1.to_string(decimal=True, precision=3) == "2.000"
    assert angle1.to_string(decimal=True, precision=1) == "2.0"
    assert angle1.to_string(decimal=True, precision=0) == "2"

    angle2 = Angle(3.0, unit=u.hourangle)

    assert angle2.to_string(decimal=True, precision=3) == "3.000"
    assert angle2.to_string(decimal=True, precision=1) == "3.0"
    assert angle2.to_string(decimal=True, precision=0) == "3"

    angle3 = Angle(4.0, unit=u.radian)

    assert angle3.to_string(decimal=True, precision=3) == "4.000"
    assert angle3.to_string(decimal=True, precision=1) == "4.0"
    assert angle3.to_string(decimal=True, precision=0) == "4"


@pytest.mark.parametrize("sep", [":", ":.", "dms", "hms"])
@pytest.mark.parametrize(
    "angle",
    [
        Angle(np.pi / 12, "rad"),
        Angle(15, "deg"),
        Angle(15, "hourangle"),
    ],
)
def test_angle_to_string_decimal_with_sep_error(angle, sep):
    # see https://github.com/astropy/astropy/pull/16085#discussion_r1501177163
    with pytest.raises(
        ValueError,
        match=rf"With decimal=True, separator cannot be used \(got sep='{sep}'\)",
    ):
        angle.to_string(sep=sep, decimal=True)


def test_to_string_formats():
    a = Angle(1.113355, unit=u.deg)
    latex_str = r"$1^\circ06{}^\prime48.078{}^{\prime\prime}$"
    assert a.to_string(format="latex") == latex_str
    assert a.to_string(format="latex_inline") == latex_str
    assert a.to_string(format="unicode") == "1°06′48.078″"

    a = Angle(1.113355, unit=u.hour)
    latex_str = r"$1^{\mathrm{h}}06^{\mathrm{m}}48.078^{\mathrm{s}}$"
    assert a.to_string(format="latex") == latex_str
    assert a.to_string(format="latex_inline") == latex_str
    assert a.to_string(format="unicode") == "1ʰ06ᵐ48.078ˢ"

    a = Angle(1.113355, unit=u.radian)
    assert a.to_string(format="latex") == r"$1.11336\;\mathrm{rad}$"
    assert a.to_string(format="latex_inline") == r"$1.11336\;\mathrm{rad}$"
    assert a.to_string(format="unicode") == "1.11336 rad"


def test_to_string_decimal_formats():
    angle1 = Angle(2.0, unit=u.degree)

    assert angle1.to_string(decimal=True, format="generic") == "2 deg"
    assert angle1.to_string(decimal=True, format="latex") == "$2\\mathrm{{}^{\\circ}}$"
    assert angle1.to_string(decimal=True, format="unicode") == "2°"

    angle2 = Angle(3.0, unit=u.hourangle)
    assert angle2.to_string(decimal=True, format="generic") == "3 hourangle"
    assert angle2.to_string(decimal=True, format="latex") == "$3\\mathrm{{}^{h}}$"
    assert angle2.to_string(decimal=True, format="unicode") == "3ʰ"

    angle3 = Angle(4.0, unit=u.radian)

    assert angle3.to_string(decimal=True, format="generic") == "4 rad"
    assert angle3.to_string(decimal=True, format="latex") == "$4\\;\\mathrm{rad}$"
    assert angle3.to_string(decimal=True, format="unicode") == "4 rad"

    with pytest.raises(ValueError, match="Unknown format"):
        angle3.to_string(decimal=True, format="myformat")


def test_to_string_fields():
    a = Angle(1.113355, unit=u.deg)
    assert a.to_string(fields=1) == r"1d"
    assert a.to_string(fields=2) == r"1d07m"
    assert a.to_string(fields=3) == r"1d06m48.078s"


def test_to_string_padding():
    a = Angle(0.5653, unit=u.deg)
    assert a.to_string(unit="deg", sep=":", pad=True) == r"00:33:55.08"

    # Test to make sure negative angles are padded correctly
    a = Angle(-0.5653, unit=u.deg)
    assert a.to_string(unit="deg", sep=":", pad=True) == r"-00:33:55.08"


def test_sexagesimal_rounding_up():
    a = Angle(359.999999999999, unit=u.deg)

    assert a.to_string(precision=None) == "360d00m00s"
    assert a.to_string(precision=4) == "360d00m00.0000s"
    assert a.to_string(precision=5) == "360d00m00.00000s"
    assert a.to_string(precision=6) == "360d00m00.000000s"
    assert a.to_string(precision=7) == "360d00m00.0000000s"
    assert a.to_string(precision=8) == "360d00m00.00000000s"
    assert a.to_string(precision=9) == "359d59m59.999999996s"

    a = Angle(3.999999, unit=u.deg)
    assert a.to_string(fields=2, precision=None) == "4d00m"
    assert a.to_string(fields=2, precision=1) == "4d00m"
    assert a.to_string(fields=2, precision=5) == "4d00m"
    assert a.to_string(fields=1, precision=1) == "4d"
    assert a.to_string(fields=1, precision=5) == "4d"


def test_to_string_scalar():
    a = Angle(1.113355, unit=u.deg)
    assert isinstance(a.to_string(), str)


def test_to_string_radian_with_precision():
    """
    Regression test for a bug that caused ``to_string`` to crash for angles in
    radians when specifying the precision.
    """

    # Check that specifying the precision works
    a = Angle(3.0, unit=u.rad)
    assert a.to_string(precision=3, sep="fromunit") == "3.000 rad"


def test_sexagesimal_round_down():
    a1 = Angle(1, u.deg).to(u.hourangle)
    a2 = Angle(2, u.deg)
    assert a1.to_string() == "0h04m00s"
    assert a2.to_string() == "2d00m00s"


def test_to_string_fields_colon():
    a = Angle(1.113355, unit=u.deg)
    assert a.to_string(fields=2, sep=":") == "1:07"
    assert a.to_string(fields=3, sep=":") == "1:06:48.078"
    assert a.to_string(fields=1, sep=":") == "1"
