package org.nsomatrix.ui;

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.*;
import java.io.*;
import java.net.URI;
import java.net.http.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class ModsPanel extends JPanel {
    private final DefaultListModel<RemoteMod> remoteModsModel = new DefaultListModel<>();
    private final JList<RemoteMod> modsList;
    private final JButton fetchModsBtn;
    private final JButton downloadSelectedBtn;
    private final JComboBox<String> sourceSelector;
    private final JTextField downloadDirField;
    private final JButton chooseDownloadDirBtn;
    private final JLabel statusLabel;

    private File downloadDir = new File(System.getProperty("user.home"), "Downloads/mods");

    // Sources and their data URLs
    private final String GITHUB_API_URL = "https://api.github.com/repos/cloudkore/matrix/contents/data/MODs";
    private final String INTERNET_ARCHIVE_METADATA_URL = "https://archive.org/metadata/nsomtxmods";

    public ModsPanel() {
        setLayout(new BorderLayout(10, 10));
        setBorder(new EmptyBorder(10, 10, 10, 10));

        JLabel titleLabel = new JLabel("Mods");
        titleLabel.setFont(new Font("SansSerif", Font.BOLD, 18));
        titleLabel.setHorizontalAlignment(SwingConstants.CENTER);
        add(titleLabel, BorderLayout.NORTH);

        modsList = new JList<>(remoteModsModel);
        modsList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
        modsList.setCellRenderer(new DefaultListCellRenderer() {
            @Override
            public Component getListCellRendererComponent(JList<?> list, Object value,
                                                          int index, boolean isSelected, boolean cellHasFocus) {
                JLabel label = (JLabel) super.getListCellRendererComponent(list, value,
                        index, isSelected, cellHasFocus);
                if (value instanceof RemoteMod) {
                    label.setText(((RemoteMod) value).name);
                }
                return label;
            }
        });

        JScrollPane scrollPane = new JScrollPane(modsList);
        add(scrollPane, BorderLayout.CENTER);

        JPanel controlsPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        controlsPanel.add(new JLabel("Source:"));
        sourceSelector = new JComboBox<>(new String[]{"GitHub", "Internet Archive"});
        controlsPanel.add(sourceSelector);
        add(controlsPanel, BorderLayout.PAGE_START);

        JPanel bottomPanel = new JPanel(new BorderLayout(10, 10));
        JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));

        fetchModsBtn = new JButton("Fetch MODs");
        fetchModsBtn.addActionListener(e -> fetchMods());

        downloadSelectedBtn = new JButton("Download Selected");
        downloadSelectedBtn.setEnabled(false);
        downloadSelectedBtn.addActionListener(e -> downloadSelectedMods());

        buttonsPanel.add(fetchModsBtn);
        buttonsPanel.add(downloadSelectedBtn);

        bottomPanel.add(buttonsPanel, BorderLayout.NORTH);

        JPanel downloadDirPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        downloadDirField = new JTextField(downloadDir.getAbsolutePath(), 30);
        chooseDownloadDirBtn = new JButton("Choose Download Folder");
        chooseDownloadDirBtn.addActionListener(e -> chooseDownloadDirectory());
        downloadDirPanel.add(new JLabel("Download Folder:"));
        downloadDirPanel.add(downloadDirField);
        downloadDirPanel.add(chooseDownloadDirBtn);
        bottomPanel.add(downloadDirPanel, BorderLayout.CENTER);

        statusLabel = new JLabel(" ");
        statusLabel.setForeground(Color.GRAY);
        bottomPanel.add(statusLabel, BorderLayout.SOUTH);

        add(bottomPanel, BorderLayout.SOUTH);

        modsList.addListSelectionListener(e ->
                downloadSelectedBtn.setEnabled(!modsList.isSelectionEmpty()));

        if (!downloadDir.exists()) {
            downloadDir.mkdirs();
        }
    }

    private void fetchMods() {
        setStatus("Fetching mod list...");
        remoteModsModel.clear();

        String source = (String) sourceSelector.getSelectedItem();
        String apiUrl;
        if ("Internet Archive".equals(source)) {
            apiUrl = INTERNET_ARCHIVE_METADATA_URL;
        } else {
            apiUrl = GITHUB_API_URL;
        }

        fetchModsBtn.setEnabled(false);

        Executors.newSingleThreadExecutor().submit(() -> {
            try {
                HttpClient client = HttpClient.newHttpClient();
                HttpRequest request = HttpRequest.newBuilder()
                        .uri(URI.create(apiUrl))
                        .header("Accept", "application/vnd.github.v3+json")
                        .build();

                HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

                if (response.statusCode() != 200) {
                    SwingUtilities.invokeLater(() -> {
                        setStatus("Failed to fetch mods: HTTP " + response.statusCode());
                        fetchModsBtn.setEnabled(true);
                    });
                    return;
                }

                ObjectMapper mapper = new ObjectMapper();
                List<RemoteMod> fetchedMods = new ArrayList<>();

                if ("Internet Archive".equals(source)) {
                    JsonNode root = mapper.readTree(response.body());
                    JsonNode filesArray = root.get("files");
                    if (filesArray != null && filesArray.isArray()) {
                        for (JsonNode fileNode : filesArray) {
                            String name = fileNode.get("name").asText();
                            if (name.toLowerCase().endsWith(".jar")) {
                                String downloadUrl = "https://archive.org/download/nsomtxmods/" + name;
                                fetchedMods.add(new RemoteMod(name, downloadUrl));
                            }
                        }
                    }
                } else {
                    // GitHub
                    JsonNode root = mapper.readTree(response.body());
                    for (JsonNode node : root) {
                        String name = node.get("name").asText();
                        String downloadUrl = node.get("download_url").asText();
                        if (name.toLowerCase().endsWith(".jar")) {
                            fetchedMods.add(new RemoteMod(name, downloadUrl));
                        }
                    }
                }

                SwingUtilities.invokeLater(() -> {
                    fetchedMods.forEach(remoteModsModel::addElement);
                    setStatus("Fetched " + fetchedMods.size() + " mods from " + source);
                    fetchModsBtn.setEnabled(true);
                });

            } catch (Exception e) {
                e.printStackTrace();
                SwingUtilities.invokeLater(() -> {
                    setStatus("Error fetching mods: " + e.getMessage());
                    fetchModsBtn.setEnabled(true);
                });
            }
        });
    }

    private void downloadSelectedMods() {
        List<RemoteMod> selectedMods = modsList.getSelectedValuesList();
        setStatus("Downloading " + selectedMods.size() + " mod(s)...");

        Executors.newSingleThreadExecutor().submit(() -> {
            int successCount = 0;
            for (RemoteMod mod : selectedMods) {
                try {
                    File targetFile = new File(downloadDir, mod.name);
                    if (targetFile.exists()) {
                        // skip existing
                        continue;
                    }
                    HttpClient client = HttpClient.newHttpClient();
                    HttpRequest request = HttpRequest.newBuilder()
                            .uri(URI.create(mod.downloadUrl))
                            .build();
                    HttpResponse<InputStream> response = client.send(request, HttpResponse.BodyHandlers.ofInputStream());
                    if (response.statusCode() == 200) {
                        try (InputStream in = response.body();
                             FileOutputStream fos = new FileOutputStream(targetFile)) {
                            in.transferTo(fos);
                        }
                        successCount++;
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
            final int downloaded = successCount;
            SwingUtilities.invokeLater(() ->
                    setStatus("Downloaded " + downloaded + " mod(s)."));
        });
    }

    private void chooseDownloadDirectory() {
        JFileChooser chooser = new JFileChooser(downloadDir);
        chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        int res = chooser.showOpenDialog(this);
        if (res == JFileChooser.APPROVE_OPTION) {
            File dir = chooser.getSelectedFile();
            if (dir.exists() && dir.isDirectory()) {
                downloadDir = dir;
                downloadDirField.setText(downloadDir.getAbsolutePath());
                setStatus("Download folder set to: " + downloadDir.getAbsolutePath());
            } else {
                setStatus("Invalid directory selected.");
            }
        }
    }

    private void setStatus(String message) {
        statusLabel.setText(message);
    }

    private static class RemoteMod {
        public final String name;
        public final String downloadUrl;

        public RemoteMod(String name, String downloadUrl) {
            this.name = name;
            this.downloadUrl = downloadUrl;
        }

        @Override
        public String toString() {
            return name;
        }
    }
}

Can you add a placeholder in the empty state of modsPanel when it hasnt fetched mods

placeholder text " Select Source to fetch MODs"