package eu.jonahbauer.raytracing.render.canvas;

import eu.jonahbauer.raytracing.render.texture.Color;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;

public final class LiveCanvas implements Canvas {
    private final @NotNull Canvas delegate;
    private final @NotNull BufferedImage image;

    public LiveCanvas(@NotNull Canvas delegate) {
        this.delegate = delegate;
        this.image = new BufferedImage(delegate.getWidth(), delegate.getHeight(), BufferedImage.TYPE_INT_RGB);
    }

    @Override
    public int getWidth() {
        return delegate.getWidth();
    }

    @Override
    public int getHeight() {
        return delegate.getHeight();
    }

    @Override
    public void set(int x, int y, @NotNull Color color) {
        delegate.set(x, y, color);
        var rgb = color.red() << 16 | color.green() << 8 | color.blue();
        image.setRGB(x, y, rgb);
    }

    @Override
    public @NotNull Color get(int x, int y) {
        return delegate.get(x, y);
    }

    public @NotNull Thread preview() {
        var frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setContentPane(new JPanel() {
            {
                setPreferredSize(new Dimension(image.getWidth(), image.getHeight()));
            }

            @Override
            protected void paintComponent(Graphics g) {
                g.drawImage(image, 0, 0, null);
            }
        });
        frame.setResizable(false);
        frame.pack();
        frame.setVisible(true);

        var update = Thread.ofVirtual().start(() -> {
            while (!Thread.interrupted()) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ex) {
                    break;
                }
                frame.repaint();
            }
            frame.dispose();
        });

        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                update.interrupt();
            }
        });

        return update;
    }
}
