# Path: acpype/mol.py
# class Angle:
# 
#     """
#     attributes: 3 Atoms, spring constant (kcal/mol/rad^2), angle eq. (rad)
#     """
# 
#     def __init__(self, atoms, kTheta, thetaEq):
#         self.atoms = atoms
#         self.kTheta = kTheta
#         self.thetaEq = thetaEq  # rad, to convert to degree: thetaEq * 180/Pi
# 
#     def __str__(self):
#         return f"<{self.atoms}, ang={self.thetaEq * 180 / Pi:.2f}>"
# 
#     def __repr__(self):
#         return f"<{self.atoms}, ang={self.thetaEq * 180 / Pi:.2f}>"
# 
# class Atom:
#     r"""
#     Atom Object Definition
# 
#     Charges in *prmtop* file are divided by ``18.2223`` to be converted
#     in units of the electron charge.
# 
#     To convert ``ACOEF`` and ``BCOEF`` to ``r0`` (Å) and ``epsilon`` (ε: kcal/mol), as seen
#     in ``gaff.dat`` for example, for a same atom type (``i = j``):
# 
#     .. math::
#         r_0 &= 1/2 * (2 * A_{coef}/B_{coef})^{1/6} \\
#         \epsilon &= 1/(4 * A_{coef}) * B_{coef}^2
# 
#     To convert ``r0`` and ``epsilon`` to ``ACOEF`` and ``BCOEF``:
# 
#     .. math::
#         A_{coef} &= \sqrt{\epsilon_i * \epsilon_j} * (r_{0i} + r_{0j})^{12} \\
#         B_{coef} &= 2 * \sqrt{\epsilon_i * \epsilon_j} * (r_{0i} + r_{0j})^6 \\
#                           &= 2 * A_{coef}/(r_{0i} + r_{0j})^6
# 
#     where index ``i`` and ``j`` for atom types.
#     Coordinates are given in Å and masses in Atomic Mass Unit.
# 
#     Returns:
#         acpype.mol.Atom: atom object
#     """
# 
#     def __init__(
#         self, atomName: str, atomType: AtomType, id_: int, resid: int, mass: float, charge: float, coord: List[float]
#     ):
#         """
#         Args:
#             atomName (str): atom name
#             atomType (AtomType): atomType object
#             id_ (int): atom number index
#             resid (int): residues number index
#             mass (float): atom mass
#             charge (float): atom charge
#             coord (List[float]): atom (x,y,z) coordinates
#         """
#         self.atomName = atomName
#         self.atomType = atomType
#         self.id = id_
#         self.cgnr = id_
#         self.resid = resid
#         self.mass = mass
#         self.charge = charge  # / qConv
#         self.coords = coord
# 
#     def __str__(self):
#         return f"<Atom id={self.id}, name={self.atomName}, {self.atomType}>"
# 
#     def __repr__(self):
#         return f"<Atom id={self.id}, name={self.atomName}, {self.atomType}>"
# 
# class Bond:
# 
#     """
#     attributes: pair of Atoms, spring constant (kcal/mol), dist. eq. (Ang)
#     """
# 
#     def __init__(self, atoms, kBond, rEq):
#         self.atoms = atoms
#         self.kBond = kBond
#         self.rEq = rEq
# 
#     def __str__(self):
#         return f"<{self.atoms}, r={self.rEq}>"
# 
#     def __repr__(self):
#         return f"<{self.atoms}, r={self.rEq}>"
# 
# class Dihedral:
# 
#     """
#     attributes: 4 Atoms, spring constant (kcal/mol), periodicity,
#     phase (rad)
#     """
# 
#     def __init__(self, atoms, kPhi, period, phase):
#         self.atoms = atoms
#         self.kPhi = kPhi
#         self.period = period
#         self.phase = phase  # rad, to convert to degree: kPhi * 180/Pi
# 
#     def __str__(self):
#         return f"<{self.atoms}, ang={self.phase * 180 / Pi:.2f}>"
# 
#     def __repr__(self):
#         return f"<{self.atoms}, ang={self.phase * 180 / Pi:.2f}>"


from acpype.mol import Angle, Atom, Bond, Dihedral

r = "<[<Atom id=3, name=C1, c3>, <Atom id=4, name=H, hc>, <Atom id=5, name=H, hc>, <Atom id=6, name=H, hc>], ang=0.00>"


def test_atom():
    atom = Atom("C1", "c3", 3, 5, 12.0, 0.5, (1.0, 0.9, 0.5))
    assert str(atom) == "<Atom id=3, name=C1, c3>"


def test_bond():
    a1 = Atom("C1", "c3", 3, 5, 12.0, 0.5, (1.0, 0.9, 0.5))
    a2 = Atom("H", "hc", 4, 5, 1.0, -0.5, (2.0, 1.9, 1.5))
    bond = Bond([a1, a2], 330.0, 1.0969)
    assert str(bond) == repr(bond) == "<[<Atom id=3, name=C1, c3>, <Atom id=4, name=H, hc>], r=1.0969>"


def test_angle():
    a1 = Atom("C1", "c3", 3, 5, 12.0, 0.5, (1.0, 0.9, 0.5))
    a2 = Atom("H", "hc", 4, 5, 1.0, -0.5, (2.0, 1.9, 1.5))
    a3 = Atom("H", "hc", 5, 5, 1.0, 0.1, (0.0, 0.1, -0.5))
    angle = Angle([a1, a2, a3], 46.3, 1.91637234)
    assert (
        str(angle)
        == repr(angle)
        == "<[<Atom id=3, name=C1, c3>, <Atom id=4, name=H, hc>, <Atom id=5, name=H, hc>], ang=109.80>"
    )


def test_dihedral():

# Path: acpype/mol.py
# class Angle:
# 
#     """
#     attributes: 3 Atoms, spring constant (kcal/mol/rad^2), angle eq. (rad)
#     """
# 
#     def __init__(self, atoms, kTheta, thetaEq):
#         self.atoms = atoms
#         self.kTheta = kTheta
#         self.thetaEq = thetaEq  # rad, to convert to degree: thetaEq * 180/Pi
# 
#     def __str__(self):
#         return f"<{self.atoms}, ang={self.thetaEq * 180 / Pi:.2f}>"
# 
#     def __repr__(self):
#         return f"<{self.atoms}, ang={self.thetaEq * 180 / Pi:.2f}>"
# 
# class Atom:
#     r"""
#     Atom Object Definition
# 
#     Charges in *prmtop* file are divided by ``18.2223`` to be converted
#     in units of the electron charge.
# 
#     To convert ``ACOEF`` and ``BCOEF`` to ``r0`` (Å) and ``epsilon`` (ε: kcal/mol), as seen
#     in ``gaff.dat`` for example, for a same atom type (``i = j``):
# 
#     .. math::
#         r_0 &= 1/2 * (2 * A_{coef}/B_{coef})^{1/6} \\
#         \epsilon &= 1/(4 * A_{coef}) * B_{coef}^2
# 
#     To convert ``r0`` and ``epsilon`` to ``ACOEF`` and ``BCOEF``:
# 
#     .. math::
#         A_{coef} &= \sqrt{\epsilon_i * \epsilon_j} * (r_{0i} + r_{0j})^{12} \\
#         B_{coef} &= 2 * \sqrt{\epsilon_i * \epsilon_j} * (r_{0i} + r_{0j})^6 \\
#                           &= 2 * A_{coef}/(r_{0i} + r_{0j})^6
# 
#     where index ``i`` and ``j`` for atom types.
#     Coordinates are given in Å and masses in Atomic Mass Unit.
# 
#     Returns:
#         acpype.mol.Atom: atom object
#     """
# 
#     def __init__(
#         self, atomName: str, atomType: AtomType, id_: int, resid: int, mass: float, charge: float, coord: List[float]
#     ):
#         """
#         Args:
#             atomName (str): atom name
#             atomType (AtomType): atomType object
#             id_ (int): atom number index
#             resid (int): residues number index
#             mass (float): atom mass
#             charge (float): atom charge
#             coord (List[float]): atom (x,y,z) coordinates
#         """
#         self.atomName = atomName
#         self.atomType = atomType
#         self.id = id_
#         self.cgnr = id_
#         self.resid = resid
#         self.mass = mass
#         self.charge = charge  # / qConv
#         self.coords = coord
# 
#     def __str__(self):
#         return f"<Atom id={self.id}, name={self.atomName}, {self.atomType}>"
# 
#     def __repr__(self):
#         return f"<Atom id={self.id}, name={self.atomName}, {self.atomType}>"
# 
# class Bond:
# 
#     """
#     attributes: pair of Atoms, spring constant (kcal/mol), dist. eq. (Ang)
#     """
# 
#     def __init__(self, atoms, kBond, rEq):
#         self.atoms = atoms
#         self.kBond = kBond
#         self.rEq = rEq
# 
#     def __str__(self):
#         return f"<{self.atoms}, r={self.rEq}>"
# 
#     def __repr__(self):
#         return f"<{self.atoms}, r={self.rEq}>"
# 
# class Dihedral:
# 
#     """
#     attributes: 4 Atoms, spring constant (kcal/mol), periodicity,
#     phase (rad)
#     """
# 
#     def __init__(self, atoms, kPhi, period, phase):
#         self.atoms = atoms
#         self.kPhi = kPhi
#         self.period = period
#         self.phase = phase  # rad, to convert to degree: kPhi * 180/Pi
# 
#     def __str__(self):
#         return f"<{self.atoms}, ang={self.phase * 180 / Pi:.2f}>"
# 
#     def __repr__(self):
#         return f"<{self.atoms}, ang={self.phase * 180 / Pi:.2f}>"


# Path: tests/test_mol.py
from acpype.mol import Angle, Atom, Bond, Dihedral


r = "<[<Atom id=3, name=C1, c3>, <Atom id=4, name=H, hc>, <Atom id=5, name=H, hc>, <Atom id=6, name=H, hc>], ang=0.00>"


def test_atom():
    atom = Atom("C1", "c3", 3, 5, 12.0, 0.5, (1.0, 0.9, 0.5))
    assert str(atom) == "<Atom id=3, name=C1, c3>"


def test_bond():
    a1 = Atom("C1", "c3", 3, 5, 12.0, 0.5, (1.0, 0.9, 0.5))
    a2 = Atom("H", "hc", 4, 5, 1.0, -0.5, (2.0, 1.9, 1.5))
    bond = Bond([a1, a2], 330.0, 1.0969)
    assert str(bond) == repr(bond) == "<[<Atom id=3, name=C1, c3>, <Atom id=4, name=H, hc>], r=1.0969>"


def test_angle():
    a1 = Atom("C1", "c3", 3, 5, 12.0, 0.5, (1.0, 0.9, 0.5))
    a2 = Atom("H", "hc", 4, 5, 1.0, -0.5, (2.0, 1.9, 1.5))
    a3 = Atom("H", "hc", 5, 5, 1.0, 0.1, (0.0, 0.1, -0.5))
    angle = Angle([a1, a2, a3], 46.3, 1.91637234)
    assert (
        str(angle)
        == repr(angle)
        == "<[<Atom id=3, name=C1, c3>, <Atom id=4, name=H, hc>, <Atom id=5, name=H, hc>], ang=109.80>"
    )


def test_dihedral():

    a1 = Atom("C1", "c3", 3, 5, 12.0, 0.5, (1.0, 0.9, 0.5))