import pygame
import math
import random

from datetime import datetime

def jours_depuis_j2000():
    # Référence : 1er janvier 2000 à midi UTC
    j2000 = datetime(2000, 1, 1, 12)
    maintenant = datetime.utcnow()
    delta = maintenant - j2000
    return delta.days + delta.seconds / 86400

def angle_orbital_actuel(periode_jours):
    jours = jours_depuis_j2000()
    phase = (jours % periode_jours) / periode_jours
    angle = 2 * math.pi * phase
    return angle


# ------------------- PARAMÈTRES GÉNÉRAUX -------------------
LARGEUR, HAUTEUR = 1000, 800
FPS = 60
TEMPS_ACCELERATION = 10  # jours simulés par seconde réelle

# ------------------- CORPS CÉLESTES -------------------
ASTRES = {
    "Soleil": {
        "rayon_affichage": 20,
        "couleur": (255, 200, 0),
        "x": LARGEUR // 2,
        "y": HAUTEUR // 2
    },
    "Mercure": {
        "rayon_affichage": 4,
        "couleur": (180, 180, 180),
        "distance_au_soleil": 58,
        "periode": 88,
    },
    "Vénus": {
        "rayon_affichage": 6,
        "couleur": (255, 230, 180),
        "distance_au_soleil": 108,
        "periode": 225,
    },
    "Terre": {
        "rayon_affichage": 8,
        "couleur": (100, 150, 255),
        "distance_au_soleil": 150,
        "periode": 365.25,
    },
    "Mars": {
        "rayon_affichage": 6,
        "couleur": (255, 100, 100),
        "distance_au_soleil": 228,
        "periode": 687,
    },
    "Lune": {
        "rayon_affichage": 3,
        "couleur": (200, 200, 200),
        "distance_a_la_terre": 0.384,
        "periode": 27.3,
    }
}

FACTEUR_VISUEL_LUNE = 20

# ------------------- INIT PYGAME -------------------
pygame.init()
fenetre = pygame.display.set_mode((LARGEUR, HAUTEUR))
pygame.display.set_caption("Simulation : système solaire (simplifié)")
clock = pygame.time.Clock()
font = pygame.font.SysFont("Arial", 14)

# ------------------- ÉTOILES -------------------
ETOILES = []
for _ in range(300):
    x = random.randint(0, LARGEUR)
    y = random.randint(0, HAUTEUR)
    taille = random.randint(1, 2)
    luminosite = random.randint(100, 255)
    ETOILES.append((x, y, taille, (luminosite, luminosite, luminosite)))

# ------------------- FONCTIONS -------------------
def dessiner_etoiles(surface):
    for x, y, taille, couleur in ETOILES:
        pygame.draw.circle(surface, couleur, (x, y), taille)

def calcul_position_orbitale(cx, cy, distance, periode, temps):
    angle = 2 * math.pi * (temps % periode) / periode
    x = cx + distance * math.cos(angle)
    y = cy + distance * math.sin(angle)
    return x, y

def couleur_de_distance(distance, d_min, d_max):
    """Retourne une couleur du bleu (proche) au rouge (loin) selon la distance"""
    if d_max == d_min:
        return (255, 255, 255)  # pour éviter division par zéro
    ratio = (distance - d_min) / (d_max - d_min)
    r = int(255 * ratio)
    g = 0
    b = int(255 * (1 - ratio))
    return (r, g, b)

def dessiner_ligne_pointillee(surface, couleur, depart, arrivee, longueur=5, espace=5):
    x1, y1 = depart
    x2, y2 = arrivee
    dx = x2 - x1
    dy = y2 - y1
    distance = math.hypot(dx, dy)
    nb_segments = int(distance // (longueur + espace))
    for i in range(nb_segments):
        start_x = x1 + (dx / distance) * (i * (longueur + espace))
        start_y = y1 + (dy / distance) * (i * (longueur + espace))
        end_x = x1 + (dx / distance) * (i * (longueur + espace) + longueur)
        end_y = y1 + (dy / distance) * (i * (longueur + espace) + longueur)
        pygame.draw.line(surface, couleur, (start_x, start_y), (end_x, end_y))

# ------------------- SIMULATION -------------------
def main():
    temps_simule = 0
    running = True
    ECHELLE = 250 / ASTRES["Terre"]["distance_au_soleil"]

    # Initialisation des lignes de départ et compteurs de révolutions
    lignes_depart = {}
    tours_effectues = {}
    for nom in ["Mercure", "Vénus", "Terre", "Mars"]:
        tours_effectues[nom] = 0

    # Calcul théorique des distances min et max entre orbites
    R_terre = ASTRES["Terre"]["distance_au_soleil"] * ECHELLE
    R_mars = ASTRES["Mars"]["distance_au_soleil"] * ECHELLE
    distance_min = abs(R_mars - R_terre)
    distance_max = R_mars + R_terre
    
    sonde_active = False
    sonde_position = None
    sonde_direction = None
    sonde_vitesse = 0.5  # pixels par frame (ajustable)
    sonde_arrivee = False

    temps_simule = jours_depuis_j2000()  # jours simulés depuis J2000

    # Calcul des angles initiaux de chaque planète
    angles_initiaux = {
        nom: angle_orbital_actuel(ASTRES[nom]["periode"])
        for nom in ["Mercure", "Vénus", "Terre", "Mars"]
    }


    while running:
        dt = clock.tick(FPS) / 1000
        temps_simule += dt * TEMPS_ACCELERATION

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False

        fenetre.fill((0, 0, 10))
        dessiner_etoiles(fenetre)

        soleil_x = ASTRES["Soleil"]["x"]
        soleil_y = ASTRES["Soleil"]["y"]

        positions = {}

        # Planètes autour du Soleil
        for nom in ["Mercure", "Vénus", "Terre", "Mars"]:
            dist = ASTRES[nom]["distance_au_soleil"] * ECHELLE
            periode = ASTRES[nom]["periode"]
            x, y = calcul_position_orbitale(soleil_x, soleil_y, dist, periode, temps_simule)
            positions[nom] = (x, y)

            # Enregistrement position de départ (ligne pointillée)
            if nom not in lignes_depart:
                lignes_depart[nom] = (int(x), int(y))

            # Compteur de tours
            tours = int(temps_simule // periode)
            tours_effectues[nom] = tours

            # Orbite
            pygame.draw.circle(fenetre, (60, 60, 60), (soleil_x, soleil_y), int(dist), 1)
            # Corps céleste
            pygame.draw.circle(fenetre, ASTRES[nom]["couleur"], (int(x), int(y)), ASTRES[nom]["rayon_affichage"])
            # Nom
            label = font.render(nom, True, ASTRES[nom]["couleur"])
            fenetre.blit(label, (x + 10, y))
            
            # Affichage du nombre de tours
            tours_texte = font.render(f"{tours} tour(s)", True, (200, 200, 200))
            fenetre.blit(tours_texte, (x + 10, y + 15))

        # --- Calcul de la distance Terre–Mars ---
        terre_pos = positions["Terre"]
        mars_pos = positions["Mars"]

        dx = mars_pos[0] - terre_pos[0]
        dy = mars_pos[1] - terre_pos[1]
        distance_tm = math.hypot(dx, dy)

        # Lancement automatique si distance proche du minimum (dans une marge)        
        if not sonde_active and distance_tm - distance_min < 5:
            sonde_active = True
            sonde_arrivee = False
            sonde_position = list(terre_pos)  # position de départ = Terre

            # Calcul du vecteur de direction unitaire vers Mars
            vecteur = (mars_pos[0] - terre_pos[0], mars_pos[1] - terre_pos[1])
            norme = math.hypot(*vecteur)
            sonde_direction = (vecteur[0]/norme, vecteur[1]/norme)

        if sonde_active and not sonde_arrivee:
            # Déplacer la sonde
            sonde_position[0] += sonde_direction[0] * sonde_vitesse
            sonde_position[1] += sonde_direction[1] * sonde_vitesse

            # Vérifier si arrivée proche de Mars
            dx = mars_pos[0] - sonde_position[0]
            dy = mars_pos[1] - sonde_position[1]
            if math.hypot(dx, dy) < 5:
                sonde_arrivee = True

        if sonde_active:
            pygame.draw.circle(fenetre, (255, 255, 0), (int(sonde_position[0]), int(sonde_position[1])), 4)
            if not sonde_arrivee:
                statut = "Sonde en route vers Mars"
            else:
                statut = "Sonde arrivée sur Mars !"
            texte_sonde = font.render(statut, True, (255, 255, 0))
            fenetre.blit(texte_sonde, (10, 50))

        # Mettre à jour min/max
        if distance_min is None or distance_tm < distance_min:
            distance_min = distance_tm
        if distance_max is None or distance_tm > distance_max:
            distance_max = distance_tm

        # Couleur de la ligne selon la distance
        couleur_liaison = couleur_de_distance(distance_tm, distance_min, distance_max)

        # Dessiner la ligne
        pygame.draw.line(fenetre, couleur_liaison, terre_pos, mars_pos, 2)

        # Affichage de la distance
        distance_mkm = distance_tm / ECHELLE  # conversion pixels -> millions de km
        texte_dist = font.render(f"Distance Terre–Mars : {distance_mkm:.1f} Mkm", True, couleur_liaison)
        fenetre.blit(texte_dist, (10, 30))

        # Lune autour de la Terre
        terre_x, terre_y = positions["Terre"]
        dist_lune = ASTRES["Lune"]["distance_a_la_terre"] * ECHELLE * FACTEUR_VISUEL_LUNE
        periode_lune = ASTRES["Lune"]["periode"]
        lune_x, lune_y = calcul_position_orbitale(terre_x, terre_y, dist_lune, periode_lune, temps_simule)

        pygame.draw.circle(fenetre, (60, 60, 60), (int(terre_x), int(terre_y)), int(dist_lune), 1)
        pygame.draw.circle(fenetre, ASTRES["Lune"]["couleur"], (int(lune_x), int(lune_y)), ASTRES["Lune"]["rayon_affichage"])
        fenetre.blit(font.render("Lune", True, ASTRES["Lune"]["couleur"]), (lune_x + 8, lune_y))

        # Soleil
        pygame.draw.circle(fenetre, ASTRES["Soleil"]["couleur"], (soleil_x, soleil_y), ASTRES["Soleil"]["rayon_affichage"])
        fenetre.blit(font.render("Soleil", True, ASTRES["Soleil"]["couleur"]), (soleil_x + 10, soleil_y))

        for nom, (x0, y0) in lignes_depart.items():
            pygame.draw.circle(fenetre, (100, 100, 100), (x0, y0), 2)
            dessiner_ligne_pointillee(fenetre, (100, 100, 100), (soleil_x, soleil_y), (x0, y0))

        # Temps simulé
        texte = font.render(f"Temps simulé : {temps_simule:.1f} jours", True, (255, 255, 255))
        fenetre.blit(texte, (10, 10))

        pygame.display.flip()

    pygame.quit()

if __name__ == "__main__":
    main()
