# Quantum Matrix Rain with Trails

import pygame
import os
import json
import random
import colorsys
from entropy_pool import load_pool as load_entropy_pool

def matrix_rain():
    pool = load_entropy_pool()
    if not pool:
        return

    pygame.init()
    WIDTH, HEIGHT = 800, 600
    screen = pygame.display.set_mode((WIDTH, HEIGHT), pygame.RESIZABLE)
    pygame.display.set_caption("Quantum Matrix Rain with Trails")

    font = pygame.font.SysFont('Consolas', 18)
    columns = screen.get_width() // 18
    drops = [0 for _ in range(columns)]
    trails = [[] for _ in range(columns)]  # 🌀 Add trail lists for each column

    clock = pygame.time.Clock()
    pool_index = 0
    hue_offset = 0.0  # Start hue at 0 degrees (green)
    frame_count = 0   # ✅ Initialize counter

    running = True

    while running:
        # Slight fade overlay (makes the trails ghostly)
        screen.fill((0, 0, 0))
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            elif event.type == pygame.VIDEORESIZE:
                WIDTH, HEIGHT = event.size
                screen = pygame.display.set_mode((WIDTH, HEIGHT), pygame.RESIZABLE)
                
                columns = WIDTH // 18  # Recalculate columns

                # Adjust drops and trails
                if len(drops) < columns:
                    drops.extend([0 for _ in range(columns - len(drops))])
                    trails.extend([[] for _ in range(columns - len(trails))])
                elif len(drops) > columns:
                    drops = drops[:columns]
                    trails = trails[:columns]
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_f:
                    pygame.display.toggle_fullscreen()

        for i in range(len(drops)):
            if not pool:
                running = False
                break

            # Burn entropy: pop one value
            value = pool.pop(0)

            # Occasionally save updated pool back to disk
            if i == len(drops) - 1:  # only once per frame
                frame_count += 1
                if frame_count % 10 == 0:  # every 10 frames
                    with open("qrng_pool.json", "w") as f:
                        json.dump({"pool": pool}, f)

            char = chr(33 + (value % 94))  # ASCII printable characters
            brightness = value  # Entropy-driven brightness
            hue = (hue_offset + (value / 256)) % 1.0  # Mix pool value with hue offset
            r, g, b = colorsys.hsv_to_rgb(hue, 1.0, brightness / 255)
            color = (int(r * 255), int(g * 255), int(b * 255))

            # Current drop position
            x = i * 18
            y = drops[i] * 18

            # Draw the head of the drop
            text = font.render(char, True, color)
            screen.blit(text, (x, y))

            # Add current position to trail
            trails[i].append((x, y, brightness))

            # Maintain trail length (entropy-driven)
            max_trail_len = 10 + (value % 10)  # Length between 10-19
            if len(trails[i]) > max_trail_len:
                trails[i].pop(0)

            # Draw the trail (fading older ones)
            for j, (tx, ty, t_brightness) in enumerate(trails[i]):
                fade = max(0, min(255, int(t_brightness * (j / max_trail_len))))
                trail_hue = (hue_offset + (value / 256)) % 1.0
                r, g, b = colorsys.hsv_to_rgb(trail_hue, 1.0, fade / 255)
                trail_color = (int(r * 255), int(g * 255), int(b * 255))

                trail_char = chr(33 + ((value + j) % 94))
                trail_text = font.render(trail_char, True, trail_color)
                screen.blit(trail_text, (tx, ty))

            # Move drop down
            drops[i] += 1
            if drops[i] * 18 > HEIGHT or random.random() > 0.975:
                drops[i] = 0
                trails[i] = []  # Reset trail when drop resets

            pool_index += 1

            hue_offset += 0.002  # Adjust for speed of cycling
            if hue_offset > 1.0:
                hue_offset = 0.0  # Loop back around

        pygame.display.flip()
        clock.tick(30)

    pygame.quit()

def run():
    matrix_rain()
