package cz.kamma.kfmanager.ui;

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

public class ProgressDialog extends JDialog {
    private final JProgressBar progressBar;
    private final JLabel statusLabel;
    private final JLabel speedLabel;
    private final JButton pauseButton;
    private final JButton cancelButton;
    
    private volatile boolean cancelled = false;
    private volatile boolean paused = false;
    private long startTime = -1;

    public ProgressDialog(Frame owner, String title) {
        super(owner, title, true);
        
        setLayout(new BorderLayout(10, 10));
        ((JPanel)getContentPane()).setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));

        JPanel infoPanel = new JPanel(new GridLayout(2, 1, 5, 5));
        statusLabel = new JLabel("Starting...");
        speedLabel = new JLabel("Speed: 0 B/s");
        infoPanel.add(statusLabel);
        infoPanel.add(speedLabel);
        add(infoPanel, BorderLayout.NORTH);

        progressBar = new JProgressBar(0, 100);
        progressBar.setStringPainted(true);
        progressBar.setPreferredSize(new Dimension(400, 25));
        add(progressBar, BorderLayout.CENTER);

        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        pauseButton = new JButton("Pause");
        cancelButton = new JButton("Cancel");

        pauseButton.addActionListener(e -> {
            paused = !paused;
            pauseButton.setText(paused ? "Resume" : "Pause");
            if (!paused) {
                synchronized(this) {
                    this.notifyAll();
                }
            }
        });

        cancelButton.addActionListener(e -> {
            cancelled = true;
            paused = false;
            cancelButton.setEnabled(false);
            statusLabel.setText("Cancelling...");
            synchronized(this) {
                this.notifyAll();
            }
        });

        buttonPanel.add(pauseButton);
        buttonPanel.add(cancelButton);
        add(buttonPanel, BorderLayout.SOUTH);

        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                cancelled = true;
            }
        });

        pack();
        setMinimumSize(new Dimension(450, getHeight()));
        setLocationRelativeTo(owner);
    }

    public void cancel() {
        cancelled = true;
    }

    private boolean displayAsBytes = false;

    public void setDisplayAsBytes(boolean displayAsBytes) {
        this.displayAsBytes = displayAsBytes;
    }

    public void updateProgress(long current, long total, String fileName) {
        if (startTime == -1) {
            startTime = System.currentTimeMillis();
        }
        
        SwingUtilities.invokeLater(() -> {
            if (total > 0) {
                progressBar.setIndeterminate(false);
                int percent = (int) ((double) current / total * 100);
                progressBar.setValue(percent);
                if (displayAsBytes) {
                    progressBar.setString(formatSize(current) + " / " + formatSize(total) + " (" + percent + "%)");
                    
                    long elapsed = System.currentTimeMillis() - startTime;
                    if (elapsed > 0) {
                        long bytesPerSec = (long) (current / (elapsed / 1000.0));
                        speedLabel.setText("Speed: " + formatSize(bytesPerSec) + "/s");
                    }
                } else {
                    progressBar.setString(current + " / " + total + " (" + percent + "%)");
                    speedLabel.setText("");
                }
            } else {
                progressBar.setIndeterminate(true);
                speedLabel.setText("");
            }
            statusLabel.setText(fileName);
        });
        
        checkState();
    }

    private String formatSize(long bytes) {
        if (bytes < 1024) return bytes + " B";
        int exp = (int) (Math.log(bytes) / Math.log(1024));
        char pre = "KMGTPE".charAt(exp - 1);
        return String.format("%.1f %cB", bytes / Math.pow(1024, exp), pre);
    }

    private void checkState() {
        if (paused && !cancelled) {
            synchronized(this) {
                while (paused && !cancelled) {
                    try {
                        this.wait(100);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            }
        }
    }

    public boolean isCancelled() {
        return cancelled;
    }
}
