import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;

public class StarfieldZoom extends JPanel implements ActionListener, KeyListener, MouseWheelListener {
    private static final int WIDTH = 800;
    private static final int HEIGHT = 600;
    private static final int NUM_STARS = 500;
    
    private Star[] stars;
    private double speed = 2.0;
    private Timer timer;
    private Random random;
    
    private class Star {
        double x, y, z;
        
        Star() {
            reset();
        }
        
        void reset() {
            x = random.nextDouble() * 2 - 1; // -1 to 1
            y = random.nextDouble() * 2 - 1; // -1 to 1
            z = random.nextDouble(); // 0 to 1
        }
        
        void update() {
            z -= speed * 0.001;
            if (z <= 0) {
                reset();
                z = 1;
            }
        }
        
        void draw(Graphics2D g2d) {
            if (z <= 0) return;
            
            // Project 3D to 2D
            double k = 128 / z;
            int px = (int)(x * k + WIDTH / 2);
            int py = (int)(y * k + HEIGHT / 2);
            
            // Check if star is on screen
            if (px < 0 || px >= WIDTH || py < 0 || py >= HEIGHT) {
                reset();
                return;
            }
            
            // Size and brightness based on depth
            int size = (int)((1 - z) * 3) + 1;
            int brightness = (int)((1 - z) * 255);
            brightness = Math.min(255, Math.max(0, brightness));
            
            g2d.setColor(new Color(brightness, brightness, brightness));
            g2d.fillOval(px - size / 2, py - size / 2, size, size);
            
            // Draw motion trail
            double prevZ = z + speed * 0.001;
            if (prevZ < 1) {
                double prevK = 128 / prevZ;
                int prevX = (int)(x * prevK + WIDTH / 2);
                int prevY = (int)(y * prevK + HEIGHT / 2);
                
                g2d.setColor(new Color(brightness / 2, brightness / 2, brightness / 2));
                g2d.drawLine(px, py, prevX, prevY);
            }
        }
    }
    
    public StarfieldZoom() {
        setPreferredSize(new Dimension(WIDTH, HEIGHT));
        setBackground(Color.BLACK);
        setFocusable(true);
        addKeyListener(this);
        addMouseWheelListener(this);
        
        random = new Random();
        stars = new Star[NUM_STARS];
        for (int i = 0; i < NUM_STARS; i++) {
            stars[i] = new Star();
        }
        
        timer = new Timer(16, this); // ~60 FPS
        timer.start();
    }
    
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        
        // Draw stars
        for (Star star : stars) {
            star.draw(g2d);
        }
        
        // Draw controls
        g2d.setColor(Color.WHITE);
        g2d.setFont(new Font("Arial", Font.PLAIN, 12));
        g2d.drawString("Speed: " + String.format("%.1f", speed), 10, 20);
        g2d.drawString("Up/Down arrows or Mouse Wheel to adjust speed", 10, 40);
        g2d.drawString("Space to reset", 10, 60);
    }
    
    @Override
    public void actionPerformed(ActionEvent e) {
        for (Star star : stars) {
            star.update();
        }
        repaint();
    }
    
    @Override
    public void keyPressed(KeyEvent e) {
        switch (e.getKeyCode()) {
            case KeyEvent.VK_UP:
                speed = Math.min(20, speed + 0.5);
                break;
            case KeyEvent.VK_DOWN:
                speed = Math.max(0.1, speed - 0.5);
                break;
            case KeyEvent.VK_SPACE:
                for (Star star : stars) {
                    star.reset();
                }
                break;
        }
    }
    
    @Override
    public void keyTyped(KeyEvent e) {}
    
    @Override
    public void keyReleased(KeyEvent e) {}
    
    @Override
    public void mouseWheelMoved(MouseWheelEvent e) {
        if (e.getWheelRotation() < 0) {
            speed = Math.min(20, speed + 0.3);
        } else {
            speed = Math.max(0.1, speed - 0.3);
        }
    }
    
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("Starfield Zoom Flythrough");
            StarfieldZoom starfield = new StarfieldZoom();
            frame.add(starfield);
            frame.pack();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
}