from fastapi import APIRouter, Depends, HTTPException
from datetime import datetime
import swisseph as swe

from db import get_db_connection
from auth_routes import get_current_user
from astrology import calculate_planets

router = APIRouter(prefix="/user", tags=["User Horoscope"])


ZODIAC_SYMBOLS = {
    "Aries": "♈",
    "Taurus": "♉",
    "Gemini": "♊",
    "Cancer": "♋",
    "Leo": "♌",
    "Virgo": "♍",
    "Libra": "♎",
    "Scorpio": "♏",
    "Sagittarius": "♐",
    "Capricorn": "♑",
    "Aquarius": "♒",
    "Pisces": "♓",
}

MONTH_NAMES = {
    1: "January",
    2: "February",
    3: "March",
    4: "April",
    5: "May",
    6: "June",
    7: "July",
    8: "August",
    9: "September",
    10: "October",
    11: "November",
    12: "December",
}


def convert_to_24_hour(hour: int, minute: int, ampm: str):
    h = int(hour)
    m = int(minute)
    ampm_upper = ampm.upper().strip() if ampm else "PM"

    if ampm_upper == "AM" and h == 12:
        h = 0

    if ampm_upper == "PM" and h != 12:
        h += 12

    return h, m


def normalize_timezone(timezone_value):
    if timezone_value is None or timezone_value == "":
        return 5.5

    if isinstance(timezone_value, (int, float)):
        return float(timezone_value)

    timezone_text = str(timezone_value).strip()

    timezone_map = {
        "Asia/Kolkata": 5.5,
        "Asia/Calcutta": 5.5,
        "IST": 5.5,
        "UTC": 0.0,
        "Etc/UTC": 0.0,
    }

    if timezone_text in timezone_map:
        return timezone_map[timezone_text]

    try:
        return float(timezone_text)
    except Exception:
        print(f"Invalid timezone value '{timezone_value}', using default 5.5")
        return 5.5


def safe_int(value, default=1):
    try:
        return int(value)
    except Exception:
        return default


def normalize_degree(value):
    return float(value) % 360


def longitude_in_house(planet_lon, start_cusp, end_cusp):
    planet_lon = normalize_degree(planet_lon)
    start_cusp = normalize_degree(start_cusp)
    end_cusp = normalize_degree(end_cusp)

    if start_cusp <= end_cusp:
        return start_cusp <= planet_lon < end_cusp

    return planet_lon >= start_cusp or planet_lon < end_cusp


def get_house_from_cusps(planet_lon, cusps):
    if not cusps or len(cusps) < 12:
        return None

    for i in range(12):
        start_cusp = cusps[i]
        end_cusp = cusps[(i + 1) % 12]

        if longitude_in_house(planet_lon, start_cusp, end_cusp):
            return i + 1

    return None


def get_natal_house_cusps(year, month, day, hour, minute, lat, lon, timezone):
    local_hour = float(hour) + (float(minute) / 60.0)
    ut_hour = local_hour - float(timezone)

    jd_ut = swe.julday(
        int(year),
        int(month),
        int(day),
        ut_hour,
    )

    cusps, ascmc = swe.houses(
        jd_ut,
        float(lat),
        float(lon),
        b"P",
    )

    return list(cusps)


def get_house_meaning(house):
    house_num = safe_int(house, 1)

    meanings = {
        1: "identity, confidence, and personal direction",
        2: "money, values, and personal resources",
        3: "communication, learning, and short travel",
        4: "home, family, and emotional security",
        5: "creativity, romance, and self-expression",
        6: "daily routine, work, and health",
        7: "relationships, partnership, and cooperation",
        8: "emotional depth, transformation, and shared resources",
        9: "wisdom, travel, faith, and higher learning",
        10: "career, goals, and public image",
        11: "friends, community, and future plans",
        12: "rest, spirituality, healing, and reflection",
    }

    return meanings.get(house_num, "life direction and personal growth")


def moon_phase_name(angle):
    if angle < 11.25 or angle >= 348.75:
        return "New Moon"
    if angle < 78.75:
        return "Waxing Crescent Moon"
    if angle < 101.25:
        return "First Quarter Moon"
    if angle < 168.75:
        return "Waxing Gibbous Moon"
    if angle < 191.25:
        return "Full Moon"
    if angle < 258.75:
        return "Waning Gibbous Moon"
    if angle < 281.25:
        return "Last Quarter Moon"
    return "Waning Crescent Moon"


def moon_phase_text(phase_name, moon_sign, moon_house):
    house_text = get_house_meaning(moon_house)

    return (
        f"The {phase_name} in {moon_sign} brings attention to {house_text}. "
        f"Your emotions may feel more connected to this area of life today. "
        f"This is a good time to notice what your inner world is asking for and adjust your actions with patience. "
        f"The Moon's current phase encourages emotional awareness, steady progress, and thoughtful decisions."
    )


def planet_house(transit_planets, planet_name, natal_cusps):
    planet = transit_planets.get(planet_name, {})
    longitude = planet.get("longitude")

    if longitude is None:
        return planet.get("house")

    house = get_house_from_cusps(longitude, natal_cusps)
    return house or planet.get("house")


def clamp_score(score):
    return max(30, min(95, int(round(score))))


def score_by_house_focus(house, good_houses, medium_houses=None):
    medium_houses = medium_houses or []
    house = safe_int(house, 0)

    if house in good_houses:
        return 9

    if house in medium_houses:
        return 5

    return 0


def calculate_love_score(transit, natal_cusps):
    transit_planets = transit.get("planets", {})

    venus_house = planet_house(transit_planets, "venus", natal_cusps)
    mars_house = planet_house(transit_planets, "mars", natal_cusps)
    moon_house = planet_house(transit_planets, "moon", natal_cusps)

    score = 55

    # Love houses: 5 romance, 7 partnership, 8 intimacy
    score += score_by_house_focus(venus_house, [5, 7, 8], [1, 11])
    score += score_by_house_focus(mars_house, [5, 7, 8], [3, 11])
    score += score_by_house_focus(moon_house, [5, 7, 8], [4, 11])

    # Extra boost if Venus is in 5th or 7th
    if safe_int(venus_house, 0) in [5, 7]:
        score += 5

    return clamp_score(score)


def calculate_career_score(transit, natal_cusps):
    transit_planets = transit.get("planets", {})

    sun_house = planet_house(transit_planets, "sun", natal_cusps)
    mercury_house = planet_house(transit_planets, "mercury", natal_cusps)
    mars_house = planet_house(transit_planets, "mars", natal_cusps)
    jupiter_house = planet_house(transit_planets, "jupiter", natal_cusps)
    saturn_house = planet_house(transit_planets, "saturn", natal_cusps)

    score = 52

    # Career houses: 2 income, 6 job/work, 10 career
    score += score_by_house_focus(sun_house, [2, 6, 10], [3, 11])
    score += score_by_house_focus(mercury_house, [2, 6, 10], [3, 9])
    score += score_by_house_focus(mars_house, [2, 6, 10], [1, 3])
    score += score_by_house_focus(jupiter_house, [2, 6, 10], [9, 11])
    score += score_by_house_focus(saturn_house, [2, 6, 10], [1, 8])

    # Jupiter in career/money/work house gives opportunity boost
    if safe_int(jupiter_house, 0) in [2, 6, 10]:
        score += 5

    return clamp_score(score)


def calculate_health_score(transit, natal_cusps):
    transit_planets = transit.get("planets", {})

    moon_house = planet_house(transit_planets, "moon", natal_cusps)
    mars_house = planet_house(transit_planets, "mars", natal_cusps)
    saturn_house = planet_house(transit_planets, "saturn", natal_cusps)

    score = 58

    # Health houses: 1 body, 6 health/routine, 12 rest/recovery
    score += score_by_house_focus(moon_house, [1, 6, 12], [4])
    score += score_by_house_focus(mars_house, [1, 6], [3])
    score += score_by_house_focus(saturn_house, [6, 12], [1])

    # Mars in 6th/12th can create stress/restlessness
    if safe_int(mars_house, 0) in [6, 12]:
        score -= 6

    # Saturn in 6th/12th means discipline needed, reduce little
    if safe_int(saturn_house, 0) in [6, 12]:
        score -= 3

    return clamp_score(score)


def calculate_general_score(love_score, career_score, health_score):
    return clamp_score((love_score + career_score + health_score) / 3)


def score_level(score):
    score = safe_int(score, 0)

    if score < 55:
        return "low"

    if score < 75:
        return "medium"

    return "good"


def build_general_horoscope(name, natal, transit, natal_cusps=None):
    transit_planets = transit.get("planets", {})
    natal_planets = natal.get("planets", {})

    sun = transit_planets.get("sun", {})
    moon = transit_planets.get("moon", {})
    mercury = transit_planets.get("mercury", {})
    venus = transit_planets.get("venus", {})
    mars = transit_planets.get("mars", {})

    natal_moon = natal_planets.get("moon", {})

    sun_house = planet_house(transit_planets, "sun", natal_cusps)
    moon_house = planet_house(transit_planets, "moon", natal_cusps)
    mercury_house = planet_house(transit_planets, "mercury", natal_cusps)
    venus_house = planet_house(transit_planets, "venus", natal_cusps)
    mars_house = planet_house(transit_planets, "mars", natal_cusps)

    sun_sign = sun.get("sign", "")
    moon_sign = moon.get("sign", "")
    mercury_sign = mercury.get("sign", "")
    venus_sign = venus.get("sign", "")
    mars_sign = mars.get("sign", "")
    natal_moon_sign = natal_moon.get("sign", "")

    return (
        f"With the Sun transiting your {sun_house} house in {sun_sign}, {name}, your focus turns toward "
        f"{get_house_meaning(sun_house)}. The Moon moving through your {moon_house} house in {moon_sign} "
        f"highlights your emotional needs and helps you understand what requires care today. "
        f"Mercury in {mercury_sign} activates your {mercury_house} house, supporting clearer thinking, planning, "
        f"and communication. Venus in {venus_sign} brings harmony to your {venus_house} house, helping you connect "
        f"with comfort, affection, and balance. Mars in {mars_sign} energizes your {mars_house} house, encouraging "
        f"you to take practical action where effort is needed. Because your natal Moon is in {natal_moon_sign}, "
        f"emotional stability comes from staying grounded and responding thoughtfully instead of rushing. "
        f"Overall, this is a day to move with awareness, protect your energy, and take steady steps toward peace "
        f"and progress."
    )


def build_mantra(name, moon_sign, sun_sign):
    return (
        f"Embrace balance and clarity today, {name}; your {moon_sign} Moon energy and {sun_sign} Sun focus "
        f"can guide you toward calm decisions and meaningful progress."
    )


def build_love_horoscope(name, transit, natal_cusps):
    transit_planets = transit.get("planets", {})

    venus = transit_planets.get("venus", {})
    mars = transit_planets.get("mars", {})
    moon = transit_planets.get("moon", {})

    venus_sign = venus.get("sign", "")
    mars_sign = mars.get("sign", "")
    moon_sign = moon.get("sign", "")

    venus_house = planet_house(transit_planets, "venus", natal_cusps)
    mars_house = planet_house(transit_planets, "mars", natal_cusps)
    moon_house = planet_house(transit_planets, "moon", natal_cusps)

    return (
        f"Transiting Venus is in {venus_sign} moving through your {venus_house} house, {name}. "
        f"This highlights affection, attraction, and the way you connect emotionally in love. "
        f"Mars in {mars_sign} activates your {mars_house} house, adding desire, confidence, and action to relationship matters. "
        f"The Moon in {moon_sign} moving through your {moon_house} house shows where your emotional needs are strongest today. "
        f"If you are in a relationship, this is a good day to communicate with patience and warmth. "
        f"If you are single, focus on genuine connection instead of rushing attraction."
    )


def build_career_horoscope(name, transit, natal_cusps):
    transit_planets = transit.get("planets", {})

    sun = transit_planets.get("sun", {})
    mercury = transit_planets.get("mercury", {})
    mars = transit_planets.get("mars", {})
    jupiter = transit_planets.get("jupiter", {})

    sun_sign = sun.get("sign", "")
    mercury_sign = mercury.get("sign", "")
    mars_sign = mars.get("sign", "")
    jupiter_sign = jupiter.get("sign", "")

    sun_house = planet_house(transit_planets, "sun", natal_cusps)
    mercury_house = planet_house(transit_planets, "mercury", natal_cusps)
    mars_house = planet_house(transit_planets, "mars", natal_cusps)
    jupiter_house = planet_house(transit_planets, "jupiter", natal_cusps)

    return (
        f"With the Sun in {sun_sign} transiting your {sun_house} house, {name}, your focus turns toward "
        f"{get_house_meaning(sun_house)}. Mercury in {mercury_sign} moving through your {mercury_house} house "
        f"supports planning, learning, messages, and professional communication. Mars in {mars_sign} activates your "
        f"{mars_house} house, giving you drive to complete tasks and take action. Jupiter in {jupiter_sign} moving through "
        f"your {jupiter_house} house shows where growth and opportunity can open with patience. "
        f"Career-wise, today favors steady effort, clear communication, and practical decisions over impulsive moves."
    )


def build_health_horoscope(name, transit, natal_cusps):
    transit_planets = transit.get("planets", {})

    moon = transit_planets.get("moon", {})
    mars = transit_planets.get("mars", {})
    saturn = transit_planets.get("saturn", {})

    moon_sign = moon.get("sign", "")
    mars_sign = mars.get("sign", "")
    saturn_sign = saturn.get("sign", "")

    moon_house = planet_house(transit_planets, "moon", natal_cusps)
    mars_house = planet_house(transit_planets, "mars", natal_cusps)
    saturn_house = planet_house(transit_planets, "saturn", natal_cusps)

    return (
        f"The Moon in {moon_sign} moving through your {moon_house} house affects your emotional rhythm and daily energy, {name}. "
        f"Mars in {mars_sign} activating your {mars_house} house can increase motivation, but it may also create restlessness "
        f"if you push too hard. Saturn in {saturn_sign} moving through your {saturn_house} house asks for discipline, balance, "
        f"and better boundaries around your body and routine. Health-wise, today supports simple habits: steady meals, hydration, "
        f"light movement, and enough rest. Avoid overthinking or forcing progress; consistency will help you feel better."
    )


def get_birth_details_for_user(user_id: int):
    conn = get_db_connection()
    cursor = conn.cursor(dictionary=True)

    try:
        cursor.execute(
            """
            SELECT
                ubd.id,
                ubd.user_id,
                ubd.name,
                ubd.birth_year,
                ubd.birth_month,
                ubd.birth_day,
                ubd.birth_hour,
                ubd.birth_minute,
                ubd.birth_ampm,
                ubd.unknown_birth_time,
                ubd.birth_place,
                ubd.birth_lat,
                ubd.birth_lon,
                ubd.timezone,
                u.email
            FROM user_birth_details ubd
            LEFT JOIN users u ON u.id = ubd.user_id
            WHERE ubd.user_id = %s
            ORDER BY ubd.id DESC
            LIMIT 1
            """,
            (user_id,),
        )

        return cursor.fetchone()

    finally:
        cursor.close()
        conn.close()


@router.get("/daily-horoscope")
def get_daily_horoscope(current_user=Depends(get_current_user)):
    details = get_birth_details_for_user(current_user["id"])

    if not details:
        raise HTTPException(status_code=404, detail="Birth details not found.")

    if details.get("birth_lat") is None or details.get("birth_lon") is None:
        raise HTTPException(
            status_code=400,
            detail="Birth latitude and longitude are missing. Please update your birth location from settings.",
        )

    try:
        user_name = details.get("name") or "User"

        birth_hour = details.get("birth_hour") or 12
        birth_minute = details.get("birth_minute") or 0
        birth_ampm = details.get("birth_ampm") or "PM"

        if details.get("unknown_birth_time"):
            birth_hour = 12
            birth_minute = 0
            birth_ampm = "PM"

        calc_hour, calc_minute = convert_to_24_hour(
            birth_hour,
            birth_minute,
            birth_ampm,
        )

        lat = float(details["birth_lat"])
        lon = float(details["birth_lon"])
        timezone = normalize_timezone(details.get("timezone"))

        natal = calculate_planets(
            year=int(details["birth_year"]),
            month=int(details["birth_month"]),
            day=int(details["birth_day"]),
            hour=calc_hour,
            minute=calc_minute,
            second=0,
            latitude=lat,
            longitude=lon,
            tz=timezone,
        )

        natal_cusps = get_natal_house_cusps(
            year=int(details["birth_year"]),
            month=int(details["birth_month"]),
            day=int(details["birth_day"]),
            hour=calc_hour,
            minute=calc_minute,
            lat=lat,
            lon=lon,
            timezone=timezone,
        )

        today = datetime.now()

        transit = calculate_planets(
            year=today.year,
            month=today.month,
            day=today.day,
            hour=12,
            minute=0,
            second=0,
            latitude=lat,
            longitude=lon,
            tz=timezone,
        )

        natal_planets = natal.get("planets", {})
        transit_planets = transit.get("planets", {})

        natal_sun = natal_planets.get("sun", {})
        natal_moon = natal_planets.get("moon", {})
        ascendant = natal.get("ascendant", {})

        sun_sign = natal_sun.get("sign")
        moon_sign = natal_moon.get("sign")
        rising_sign = ascendant.get("sign")

        transit_sun = transit_planets.get("sun", {})
        transit_moon = transit_planets.get("moon", {})

        sun_lon = transit_sun.get("longitude", 0)
        moon_lon = transit_moon.get("longitude", 0)
        phase_angle = (moon_lon - sun_lon) % 360
        phase_name = moon_phase_name(phase_angle)

        today_date = f"{MONTH_NAMES.get(today.month, today.month)} {today.day}, {today.year}"

        birthdate_text = (
            f"{details['birth_year']}-"
            f"{str(details['birth_month']).zfill(2)}-"
            f"{str(details['birth_day']).zfill(2)}"
        )

        birth_time_text = f"{birth_hour}:{str(birth_minute).zfill(2)} {birth_ampm}"

        moon_house = get_house_from_cusps(moon_lon, natal_cusps)

        if not moon_house:
            moon_house = transit_moon.get("house")

        moon_degree = transit_moon.get("degree", "")
        moon_sign_today = transit_moon.get("sign", "")

        love_score = calculate_love_score(transit, natal_cusps)
        career_score = calculate_career_score(transit, natal_cusps)
        health_score = calculate_health_score(transit, natal_cusps)
        general_score = calculate_general_score(love_score, career_score, health_score)

        mantra = build_mantra(user_name, moon_sign or "", sun_sign or "")
        general = build_general_horoscope(user_name, natal, transit, natal_cusps)
        moon_text = moon_phase_text(phase_name, moon_sign_today, moon_house)

        love_horoscope = build_love_horoscope(user_name, transit, natal_cusps)
        career_horoscope = build_career_horoscope(user_name, transit, natal_cusps)
        health_horoscope = build_health_horoscope(user_name, transit, natal_cusps)

        return {
            "success": True,
            "name": user_name,
            "today_date": today_date,
            "birthdate": birthdate_text,
            "birth_time": birth_time_text,
            "location": details.get("birth_place") or "",
            "house_system": "Placidus",
            "sun": {
                "sign": sun_sign,
                "symbol": ZODIAC_SYMBOLS.get(sun_sign, "☉"),
                "label": f"{sun_sign} Sun" if sun_sign else "Sun",
            },
            "moon": {
                "sign": moon_sign,
                "symbol": ZODIAC_SYMBOLS.get(moon_sign, "☽"),
                "label": f"{moon_sign} Moon" if moon_sign else "Moon",
            },
            "rising": {
                "sign": rising_sign,
                "symbol": ZODIAC_SYMBOLS.get(rising_sign, "↑"),
                "label": f"{rising_sign} Rising" if rising_sign else "Rising",
            },
            "moon_phase": {
                "name": phase_name,
                "sign": moon_sign_today,
                "house": moon_house,
                "degree": moon_degree,
                "text": moon_text,
            },
            "mantra": mantra,
            "general_score": general_score,
            "general_score_level": score_level(general_score),
            "general_horoscope": general,
            "love_score": love_score,
            "love_score_level": score_level(love_score),
            "love_horoscope": love_horoscope,
            "career_score": career_score,
            "career_score_level": score_level(career_score),
            "career_horoscope": career_horoscope,
            "health_score": health_score,
            "health_score_level": score_level(health_score),
            "health_horoscope": health_horoscope,
        }

    except HTTPException:
        raise

    except Exception as e:
        print("Daily horoscope generation error:", e)
        raise HTTPException(
            status_code=500,
            detail=f"Daily horoscope generation failed: {str(e)}",
        )