MAJOR_ASPECTS = {
    "conjunction": {"angle": 0, "symbol": "☌", "orb": 8},
    "sextile": {"angle": 60, "symbol": "⚹", "orb": 6},
    "square": {"angle": 90, "symbol": "□", "orb": 8},
    "trine": {"angle": 120, "symbol": "△", "orb": 8},
    "opposition": {"angle": 180, "symbol": "☍", "orb": 8},
}

MINOR_ASPECTS = {
    "semisextile": {"angle": 30, "symbol": "⚺", "orb": 3},
    "semisquare": {"angle": 45, "symbol": "∠", "orb": 3},
    "quintile": {"angle": 72, "symbol": "⬠", "orb": 3},
    "sesquiquadrate": {"angle": 135, "symbol": "⚼", "orb": 3},
    "biquintile": {"angle": 144, "symbol": "±", "orb": 3},
    "quincunx": {"angle": 150, "symbol": "⚻", "orb": 3},
}


def format_orb(orb):
    degree = int(orb)
    minute = round((orb - degree) * 60)

    if minute == 60:
        degree += 1
        minute = 0

    return f"{degree}° {minute}'"


def angle_difference(lon1, lon2):
    diff = abs(float(lon1) - float(lon2)) % 360
    if diff > 180:
        diff = 360 - diff
    return diff


def find_aspect(lon1, lon2):
    diff = angle_difference(lon1, lon2)

    for name, data in MAJOR_ASPECTS.items():
        orb = abs(diff - data["angle"])
        if orb <= data["orb"]:
            return {
                "aspect": name,
                "symbol": data["symbol"],
                "angle": data["angle"],
                "orb": round(orb, 4),
                "orb_text": format_orb(orb),
                "type": "major",
            }

    for name, data in MINOR_ASPECTS.items():
        orb = abs(diff - data["angle"])
        if orb <= data["orb"]:
            return {
                "aspect": name,
                "symbol": data["symbol"],
                "angle": data["angle"],
                "orb": round(orb, 4),
                "orb_text": format_orb(orb),
                "type": "minor",
            }

    return None


def calculate_aspects(planets):
    """
    planets must be list:
    [
      {"planet": "Sun", "longitude": 235.48},
      {"planet": "Moon", "longitude": 158.75}
    ]
    """

    major_aspects = []
    minor_aspects = []

    for i in range(len(planets)):
        for j in range(i + 1, len(planets)):
            p1 = planets[i]
            p2 = planets[j]

            lon1 = p1.get("longitude")
            lon2 = p2.get("longitude")

            if lon1 is None or lon2 is None:
                continue

            aspect = find_aspect(lon1, lon2)

            if aspect:
                item = {
                    "planet1": p1.get("planet"),
                    "planet2": p2.get("planet"),
                    "aspect": aspect["aspect"],
                    "symbol": aspect["symbol"],
                    "angle": aspect["angle"],
                    "orb": aspect["orb"],
                    "orb_text": aspect["orb_text"],
                    "type": aspect["type"],
                    "display": f'{p1.get("planet")} {aspect["aspect"]} {p2.get("planet")} orb: {aspect["orb_text"]}',
                }

                if aspect["type"] == "major":
                    major_aspects.append(item)
                else:
                    minor_aspects.append(item)

    return {
        "major_aspects": major_aspects,
        "minor_aspects": minor_aspects,
        "aspects": major_aspects + minor_aspects,
    }


def calculate_synastry_aspects(planets_a, planets_b):
    """
    Compare planets from list A with planets from list B.
    """
    major_aspects = []
    minor_aspects = []

    for p1 in planets_a:
        for p2 in planets_b:
            lon1 = p1.get("longitude")
            lon2 = p2.get("longitude")

            if lon1 is None or lon2 is None:
                continue

            aspect = find_aspect(lon1, lon2)

            if aspect:
                item = {
                    "planet1": p1.get("planet"),
                    "planet2": p2.get("planet"),
                    "aspect": aspect["aspect"],
                    "symbol": aspect["symbol"],
                    "angle": aspect["angle"],
                    "orb": aspect["orb"],
                    "orb_text": aspect["orb_text"],
                    "type": aspect["type"],
                }

                if aspect["type"] == "major":
                    major_aspects.append(item)
                else:
                    minor_aspects.append(item)

    return {
        "major_aspects": major_aspects,
        "minor_aspects": minor_aspects,
    }