import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.*;
import javax.imageio.ImageIO;

public class CallJotsDesktop extends JFrame {
    private String apiKey = "";
    private String apiBase = "https://api.calljots.com/v1";
    private static final Color ORANGE = new Color(249, 115, 22);
    private static final Color BG = new Color(10, 14, 23);
    private static final Color SURFACE = new Color(15, 23, 42);
    private static final Color TEXT = new Color(226, 232, 240);
    private static final Color DIM = new Color(100, 116, 139);
    private static final Color BORDER = new Color(30, 41, 59);
    private static final Color GREEN = new Color(34, 197, 94);
    private static final Color RED = new Color(239, 68, 68);

    private CardLayout cardLayout = new CardLayout();
    private JPanel mainPanel = new JPanel(cardLayout);
    private JTextArea resultArea = new JTextArea();
    private JLabel statusLabel = new JLabel("Not activated");
    private JLabel keyLabel = new JLabel("");

    public CallJotsDesktop() {
        setTitle("CallJots Desktop");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(900, 650);
        setLocationRelativeTo(null);
        setMinimumSize(new Dimension(700, 500));

        try {
            java.util.List<Image> icons = new java.util.ArrayList<>();
            icons.add(Toolkit.getDefaultToolkit().getImage(
                new URL("https://calljots.com/img/favicon.svg")));
            setIconImages(icons);
        } catch (Exception e) {}

        setLayout(new BorderLayout());
        getContentPane().setBackground(BG);

        buildUI();
        showActivation();
    }

    private void buildUI() {
        // Top bar
        JPanel topBar = new JPanel(new BorderLayout());
        topBar.setBackground(SURFACE);
        topBar.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, BORDER));
        topBar.setPreferredSize(new Dimension(0, 48));

        JLabel logo = new JLabel("CallJots Desktop");
        logo.setFont(new Font("Inter", Font.BOLD, 16));
        logo.setForeground(ORANGE);
        logo.setBorder(BorderFactory.createEmptyBorder(0, 16, 0, 0));
        topBar.add(logo, BorderLayout.WEST);

        JPanel rightPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 8, 10));
        rightPanel.setBackground(SURFACE);
        rightPanel.add(keyLabel);
        keyLabel.setFont(new Font("Monospaced", Font.PLAIN, 11));
        keyLabel.setForeground(DIM);

        statusLabel.setFont(new Font("Inter", Font.PLAIN, 12));
        statusLabel.setForeground(DIM);
        rightPanel.add(statusLabel);

        JButton logoutBtn = new JButton("Lock");
        logoutBtn.setFont(new Font("Inter", Font.BOLD, 12));
        logoutBtn.setForeground(DIM);
        logoutBtn.setBackground(SURFACE);
        logoutBtn.setBorder(BorderFactory.createLineBorder(BORDER));
        logoutBtn.setFocusPainted(false);
        logoutBtn.addActionListener(e -> logout());
        rightPanel.add(logoutBtn);

        topBar.add(rightPanel, BorderLayout.EAST);
        add(topBar, BorderLayout.NORTH);

        // Sidebar
        JPanel sidebar = new JPanel();
        sidebar.setLayout(new BoxLayout(sidebar, BoxLayout.Y_AXIS));
        sidebar.setBackground(SURFACE);
        sidebar.setPreferredSize(new Dimension(200, 0));
        sidebar.setBorder(BorderFactory.createMatteBorder(0, 0, 0, 1, BORDER));

        String[] navItems = {"Extract Jots", "Transcribe Audio", "Search Jots", "View Models", "Billing", "API Console"};
        String[] navIcons = {"\u270E", "\uD83C\uDFA4", "\uD83D\uDD0D", "\u2699", "\u0024", "\u003E"};
        for (int i = 0; i < navItems.length; i++) {
            JButton btn = new JButton(navIcons[i] + "  " + navItems[i]);
            btn.setAlignmentX(Component.LEFT_ALIGNMENT);
            btn.setFont(new Font("Inter", Font.PLAIN, 13));
            btn.setForeground(DIM);
            btn.setBackground(SURFACE);
            btn.setBorder(BorderFactory.createEmptyBorder(10, 16, 10, 16));
            btn.setFocusPainted(false);
            btn.setHorizontalAlignment(SwingConstants.LEFT);
            btn.setMaximumSize(new Dimension(200, 40));
            final int idx = i;
            btn.addActionListener(e -> { cardLayout.show(mainPanel, "panel" + idx); });
            btn.addMouseListener(new java.awt.event.MouseAdapter() {
                public void mouseEntered(MouseEvent e) { btn.setBackground(new Color(20, 30, 50)); }
                public void mouseExited(MouseEvent e) { btn.setBackground(SURFACE); }
            });
            sidebar.add(btn);
        }
        sidebar.add(Box.createVerticalGlue());
        add(sidebar, BorderLayout.WEST);

        // Main content area with CardLayout
        mainPanel.setBackground(BG);
        mainPanel.add(buildActivationPanel(), "panelActivation");
        mainPanel.add(buildExtractPanel(), "panel0");
        mainPanel.add(buildTranscribePanel(), "panel1");
        mainPanel.add(buildSearchPanel(), "panel2");
        mainPanel.add(buildModelsPanel(), "panel3");
        mainPanel.add(buildBillingPanel(), "panel4");
        mainPanel.add(buildApiConsolePanel(), "panel5");
        add(mainPanel, BorderLayout.CENTER);
    }

    private JPanel buildActivationPanel() {
        JPanel panel = new JPanel(new GridBagLayout());
        panel.setBackground(BG);
        GridBagConstraints c = new GridBagConstraints();
        c.insets = new Insets(8, 8, 8, 8);
        c.gridwidth = 2;

        JLabel logo = new JLabel("CallJots Desktop");
        logo.setFont(new Font("Inter", Font.BOLD, 28));
        logo.setForeground(ORANGE);
        c.gridy = 0; panel.add(logo, c);

        JLabel sub = new JLabel("Enter your API key to begin");
        sub.setFont(new Font("Inter", Font.PLAIN, 14));
        sub.setForeground(DIM);
        c.gridy = 1; panel.add(sub, c);

        JPasswordField keyField = new JPasswordField(30);
        keyField.setFont(new Font("Monospaced", Font.PLAIN, 14));
        keyField.setBackground(SURFACE);
        keyField.setForeground(TEXT);
        keyField.setCaretColor(ORANGE);
        keyField.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(BORDER),
            BorderFactory.createEmptyBorder(10, 12, 10, 12)));
        c.gridy = 2; panel.add(keyField, c);

        JButton activateBtn = new JButton("Activate");
        activateBtn.setFont(new Font("Inter", Font.BOLD, 14));
        activateBtn.setForeground(Color.WHITE);
        activateBtn.setBackground(ORANGE);
        activateBtn.setBorder(BorderFactory.createEmptyBorder(12, 40, 12, 40));
        activateBtn.setFocusPainted(false);
        c.gridy = 3; panel.add(activateBtn, c);

        JLabel errorLabel = new JLabel("");
        errorLabel.setFont(new Font("Inter", Font.PLAIN, 13));
        errorLabel.setForeground(RED);
        c.gridy = 4; panel.add(errorLabel, c);

        activateBtn.addActionListener(e -> {
            String key = new String(keyField.getPassword()).trim();
            if (key.length() < 8) {
                errorLabel.setText("Key must be at least 8 characters");
                return;
            }
            activateBtn.setEnabled(false);
            activateBtn.setText("Verifying...");
            errorLabel.setText("");

            Executors.newSingleThreadExecutor().submit(() -> {
                try {
                    URL url = new URL(apiBase + "/auth/me");
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    conn.setRequestProperty("Authorization", "Bearer " + key);
                    conn.setRequestProperty("Accept", "application/json");
                    conn.setConnectTimeout(10000);

                    if (conn.getResponseCode() == 200) {
                        apiKey = key;
                        SwingUtilities.invokeLater(() -> {
                            keyLabel.setText("Key: " + key.substring(0, 8) + "...");
                            statusLabel.setText("Connected");
                            statusLabel.setForeground(GREEN);
                            cardLayout.show(mainPanel, "panel0");
                            errorLabel.setText("");
                        });
                    } else {
                        SwingUtilities.invokeLater(() -> {
                            errorLabel.setText("Invalid API key");
                            activateBtn.setEnabled(true);
                            activateBtn.setText("Activate");
                        });
                    }
                } catch (Exception ex) {
                    SwingUtilities.invokeLater(() -> {
                        errorLabel.setText("API unreachable: " + ex.getMessage());
                        activateBtn.setEnabled(true);
                        activateBtn.setText("Activate");
                    });
                }
            });
        });

        keyField.addActionListener(e -> activateBtn.doClick());
        return panel;
    }

    private JPanel buildExtractPanel() {
        JPanel panel = new JPanel(new BorderLayout(0, 12));
        panel.setBackground(BG);
        panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));

        JLabel title = new JLabel("\u270E  Extract Jots from Text");
        title.setFont(new Font("Inter", Font.BOLD, 18));
        title.setForeground(TEXT);
        panel.add(title, BorderLayout.NORTH);

        JTextArea input = new JTextArea(5, 40);
        input.setFont(new Font("Inter", Font.PLAIN, 14));
        input.setBackground(SURFACE);
        input.setForeground(TEXT);
        input.setCaretColor(ORANGE);
        input.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(BORDER),
            BorderFactory.createEmptyBorder(10, 12, 10, 12)));
        input.setLineWrap(true);
        JScrollPane scroll = new JScrollPane(input);
        scroll.setBorder(null);
        panel.add(scroll, BorderLayout.CENTER);

        JPanel bottom = new JPanel(new BorderLayout());
        bottom.setBackground(BG);
        JButton btn = new JButton("Extract Jots");
        btn.setFont(new Font("Inter", Font.BOLD, 14));
        btn.setForeground(Color.WHITE);
        btn.setBackground(ORANGE);
        btn.setBorder(BorderFactory.createEmptyBorder(10, 24, 10, 24));
        btn.setFocusPainted(false);
        bottom.add(btn, BorderLayout.WEST);

        JTextArea result = new JTextArea(10, 40);
        result.setFont(new Font("Monospaced", Font.PLAIN, 12));
        result.setBackground(SURFACE);
        result.setForeground(TEXT);
        result.setEditable(false);
        result.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(BORDER),
            BorderFactory.createEmptyBorder(10, 12, 10, 12)));
        JScrollPane resultScroll = new JScrollPane(result);
        resultScroll.setBorder(null);
        bottom.add(resultScroll, BorderLayout.CENTER);
        panel.add(bottom, BorderLayout.SOUTH);

        btn.addActionListener(e -> {
            String text = input.getText().trim();
            if (text.isEmpty()) return;
            btn.setEnabled(false);
            btn.setText("Extracting...");
            Executors.newSingleThreadExecutor().submit(() -> {
                try {
                    URL url = new URL(apiBase + "/jots/extract");
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    conn.setRequestMethod("POST");
                    conn.setRequestProperty("Authorization", "Bearer " + apiKey);
                    conn.setRequestProperty("Content-Type", "application/json");
                    conn.setDoOutput(true);
                    String json = "{\"text\":\"" + text.replace("\"", "\\\"") + "\",\"threshold\":0.3}";
                    conn.getOutputStream().write(json.getBytes(StandardCharsets.UTF_8));

                    String resp = readResponse(conn);
                    SwingUtilities.invokeLater(() -> {
                        result.setText(formatJson(resp));
                        btn.setEnabled(true);
                        btn.setText("Extract Jots");
                    });
                } catch (Exception ex) {
                    SwingUtilities.invokeLater(() -> {
                        result.setText("Error: " + ex.getMessage());
                        btn.setEnabled(true);
                        btn.setText("Extract Jots");
                    });
                }
            });
        });
        return panel;
    }

    private JPanel buildTranscribePanel() {
        JPanel panel = new JPanel(new BorderLayout(0, 12));
        panel.setBackground(BG);
        panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));

        JLabel title = new JLabel("\uD83C\uDFA4  Transcribe Audio");
        title.setFont(new Font("Inter", Font.BOLD, 18));
        title.setForeground(TEXT);
        panel.add(title, BorderLayout.NORTH);

        JPanel center = new JPanel(new FlowLayout(FlowLayout.LEFT, 12, 12));
        center.setBackground(BG);

        JLabel fileLabel = new JLabel("No file selected");
        fileLabel.setFont(new Font("Inter", Font.PLAIN, 13));
        fileLabel.setForeground(DIM);

        JButton fileBtn = new JButton("Choose WAV/MP3");
        fileBtn.setFont(new Font("Inter", Font.BOLD, 13));
        fileBtn.setForeground(TEXT);
        fileBtn.setBackground(SURFACE);
        fileBtn.setBorder(BorderFactory.createLineBorder(BORDER));
        fileBtn.setFocusPainted(false);
        center.add(fileBtn);
        center.add(fileLabel);

        JButton transBtn = new JButton("Transcribe & Extract Jots");
        transBtn.setFont(new Font("Inter", Font.BOLD, 14));
        transBtn.setForeground(Color.WHITE);
        transBtn.setBackground(ORANGE);
        transBtn.setBorder(BorderFactory.createEmptyBorder(10, 24, 10, 24));
        transBtn.setFocusPainted(false);
        transBtn.setEnabled(false);
        center.add(transBtn);

        panel.add(center, BorderLayout.CENTER);

        final File[] selectedFile = {null};
        fileBtn.addActionListener(e -> {
            JFileChooser chooser = new JFileChooser();
            chooser.setFileFilter(new javax.swing.filechooser.FileNameExtensionFilter(
                "Audio files (WAV, MP3, FLAC, OGG)", "wav", "mp3", "flac", "ogg"));
            if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
                selectedFile[0] = chooser.getSelectedFile();
                fileLabel.setText(selectedFile[0].getName());
                transBtn.setEnabled(true);
            }
        });

        JTextArea result = new JTextArea(12, 40);
        result.setFont(new Font("Monospaced", Font.PLAIN, 12));
        result.setBackground(SURFACE);
        result.setForeground(TEXT);
        result.setEditable(false);
        result.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(BORDER),
            BorderFactory.createEmptyBorder(10, 12, 10, 12)));
        panel.add(new JScrollPane(result), BorderLayout.SOUTH);

        transBtn.addActionListener(e -> {
            if (selectedFile[0] == null) return;
            transBtn.setEnabled(false);
            transBtn.setText("Uploading...");
            File file = selectedFile[0];
            Executors.newSingleThreadExecutor().submit(() -> {
                try {
                    String boundary = "----Boundary" + System.currentTimeMillis();
                    URL url = new URL(apiBase + "/jobs/transcribe");
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    conn.setRequestMethod("POST");
                    conn.setRequestProperty("Authorization", "Bearer " + apiKey);
                    conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
                    conn.setDoOutput(true);

                    try (OutputStream os = conn.getOutputStream();
                         FileInputStream fis = new FileInputStream(file)) {
                        os.write(("--" + boundary + "\r\n").getBytes());
                        os.write(("Content-Disposition: form-data; name=\"file\"; filename=\"" + file.getName() + "\"\r\n").getBytes());
                        os.write(("Content-Type: audio/" + file.getName().substring(file.getName().lastIndexOf('.')+1) + "\r\n\r\n").getBytes());
                        byte[] buf = new byte[8192];
                        int n;
                        while ((n = fis.read(buf)) != -1) os.write(buf, 0, n);
                        os.write(("\r\n--" + boundary + "--\r\n").getBytes());
                    }

                    String resp = readResponse(conn);
                    SwingUtilities.invokeLater(() -> {
                        result.setText(formatJson(resp));
                        transBtn.setEnabled(true);
                        transBtn.setText("Transcribe & Extract Jots");
                    });
                } catch (Exception ex) {
                    SwingUtilities.invokeLater(() -> {
                        result.setText("Error: " + ex.getMessage());
                        transBtn.setEnabled(true);
                        transBtn.setText("Transcribe & Extract Jots");
                    });
                }
            });
        });
        return panel;
    }

    private JPanel buildSearchPanel() {
        JPanel panel = new JPanel(new BorderLayout(0, 12));
        panel.setBackground(BG);
        panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));

        JLabel title = new JLabel("\uD83D\uDD0D  Search Jots");
        title.setFont(new Font("Inter", Font.BOLD, 18));
        title.setForeground(TEXT);
        panel.add(title, BorderLayout.NORTH);

        JPanel inputPanel = new JPanel(new GridBagLayout());
        inputPanel.setBackground(BG);
        GridBagConstraints c = new GridBagConstraints();
        c.insets = new Insets(4, 4, 4, 4);
        c.fill = GridBagConstraints.HORIZONTAL;

        c.gridy = 0; c.gridx = 0;
        inputPanel.add(new JLabel("Query:"), c);
        JTextField queryField = new JTextField(20);
        styleField(queryField);
        c.gridx = 1; inputPanel.add(queryField, c);

        c.gridy = 0; c.gridx = 2;
        inputPanel.add(new JLabel("Type:"), c);
        JTextField typeField = new JTextField(15);
        styleField(typeField);
        c.gridx = 3; inputPanel.add(typeField, c);

        c.gridy = 1; c.gridx = 0;
        inputPanel.add(new JLabel("Person:"), c);
        JTextField personField = new JTextField(15);
        styleField(personField);
        c.gridx = 1; inputPanel.add(personField, c);

        c.gridy = 1; c.gridx = 2;
        inputPanel.add(new JLabel("Location:"), c);
        JTextField locField = new JTextField(15);
        styleField(locField);
        c.gridx = 3; inputPanel.add(locField, c);

        c.gridy = 2; c.gridx = 0;
        inputPanel.add(new JLabel("Limit:"), c);
        JTextField limitField = new JTextField("25", 5);
        styleField(limitField);
        c.gridx = 1; inputPanel.add(limitField, c);

        JButton searchBtn = new JButton("Search");
        searchBtn.setFont(new Font("Inter", Font.BOLD, 14));
        searchBtn.setForeground(Color.WHITE);
        searchBtn.setBackground(ORANGE);
        searchBtn.setBorder(BorderFactory.createEmptyBorder(10, 24, 10, 24));
        searchBtn.setFocusPainted(false);
        c.gridy = 2; c.gridx = 3; inputPanel.add(searchBtn, c);

        panel.add(inputPanel, BorderLayout.CENTER);

        JTextArea result = new JTextArea(12, 40);
        result.setFont(new Font("Monospaced", Font.PLAIN, 12));
        result.setBackground(SURFACE);
        result.setForeground(TEXT);
        result.setEditable(false);
        result.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(BORDER),
            BorderFactory.createEmptyBorder(10, 12, 10, 12)));
        panel.add(new JScrollPane(result), BorderLayout.SOUTH);

        searchBtn.addActionListener(e -> {
            searchBtn.setEnabled(false);
            searchBtn.setText("Searching...");
            Executors.newSingleThreadExecutor().submit(() -> {
                try {
                    StringBuilder path = new StringBuilder(apiBase + "/jots/search?limit=" + limitField.getText());
                    if (!queryField.getText().isEmpty()) path.append("&q=").append(URLEncoder.encode(queryField.getText(), "UTF-8"));
                    if (!typeField.getText().isEmpty()) path.append("&jot_type=").append(typeField.getText());
                    if (!personField.getText().isEmpty()) path.append("&person=").append(URLEncoder.encode(personField.getText(), "UTF-8"));
                    if (!locField.getText().isEmpty()) path.append("&location=").append(URLEncoder.encode(locField.getText(), "UTF-8"));

                    URL url = new URL(path.toString());
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    conn.setRequestProperty("Authorization", "Bearer " + apiKey);
                    conn.setRequestProperty("Accept", "application/json");
                    String resp = readResponse(conn);
                    SwingUtilities.invokeLater(() -> {
                        result.setText(formatJson(resp));
                        searchBtn.setEnabled(true);
                        searchBtn.setText("Search");
                    });
                } catch (Exception ex) {
                    SwingUtilities.invokeLater(() -> {
                        result.setText("Error: " + ex.getMessage());
                        searchBtn.setEnabled(true);
                        searchBtn.setText("Search");
                    });
                }
            });
        });
        return panel;
    }

    private JPanel buildModelsPanel() {
        JPanel panel = new JPanel(new BorderLayout(0, 12));
        panel.setBackground(BG);
        panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));

        JLabel title = new JLabel("\u2699  Available Models");
        title.setFont(new Font("Inter", Font.BOLD, 18));
        title.setForeground(TEXT);
        panel.add(title, BorderLayout.NORTH);

        JButton refreshBtn = new JButton("Refresh Models");
        refreshBtn.setFont(new Font("Inter", Font.BOLD, 14));
        refreshBtn.setForeground(Color.WHITE);
        refreshBtn.setBackground(ORANGE);
        refreshBtn.setBorder(BorderFactory.createEmptyBorder(10, 24, 10, 24));
        refreshBtn.setFocusPainted(false);
        panel.add(refreshBtn, BorderLayout.NORTH);

        JTextArea result = new JTextArea(15, 40);
        result.setFont(new Font("Monospaced", Font.PLAIN, 12));
        result.setBackground(SURFACE);
        result.setForeground(TEXT);
        result.setEditable(false);
        result.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(BORDER),
            BorderFactory.createEmptyBorder(10, 12, 10, 12)));
        panel.add(new JScrollPane(result), BorderLayout.CENTER);

        refreshBtn.addActionListener(e -> {
            refreshBtn.setEnabled(false);
            refreshBtn.setText("Loading...");
            Executors.newSingleThreadExecutor().submit(() -> {
                try {
                    URL url = new URL(apiBase + "/models");
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    conn.setRequestProperty("Authorization", "Bearer " + apiKey);
                    conn.setRequestProperty("Accept", "application/json");
                    String resp = readResponse(conn);
                    SwingUtilities.invokeLater(() -> {
                        result.setText(formatJson(resp));
                        refreshBtn.setEnabled(true);
                        refreshBtn.setText("Refresh Models");
                    });
                } catch (Exception ex) {
                    SwingUtilities.invokeLater(() -> {
                        result.setText("Error: " + ex.getMessage());
                        refreshBtn.setEnabled(true);
                        refreshBtn.setText("Refresh Models");
                    });
                }
            });
        });
        refreshBtn.doClick();
        return panel;
    }

    private JPanel buildBillingPanel() {
        JPanel panel = new JPanel(new BorderLayout(0, 12));
        panel.setBackground(BG);
        panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));

        JLabel title = new JLabel("\u0024  Billing & Usage");
        title.setFont(new Font("Inter", Font.BOLD, 18));
        title.setForeground(TEXT);
        panel.add(title, BorderLayout.NORTH);

        JPanel btnPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 12, 0));
        btnPanel.setBackground(BG);

        JButton usageBtn = new JButton("Usage");
        styleBtn(usageBtn);
        btnPanel.add(usageBtn);

        JButton billingBtn = new JButton("Current Plan");
        styleBtn(billingBtn);
        btnPanel.add(billingBtn);

        panel.add(btnPanel, BorderLayout.NORTH);

        JTextArea result = new JTextArea(15, 40);
        result.setFont(new Font("Monospaced", Font.PLAIN, 12));
        result.setBackground(SURFACE);
        result.setForeground(TEXT);
        result.setEditable(false);
        result.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(BORDER),
            BorderFactory.createEmptyBorder(10, 12, 10, 12)));
        panel.add(new JScrollPane(result), BorderLayout.CENTER);

        Runnable loadUsage = () -> {
            try {
                URL url = new URL(apiBase + "/billing/usage");
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setRequestProperty("Authorization", "Bearer " + apiKey);
                conn.setRequestProperty("Accept", "application/json");
                String resp = readResponse(conn);
                SwingUtilities.invokeLater(() -> result.setText(formatJson(resp)));
            } catch (Exception ex) {
                SwingUtilities.invokeLater(() -> result.setText("Error: " + ex.getMessage()));
            }
        };

        Runnable loadBilling = () -> {
            try {
                URL url = new URL(apiBase + "/billing/current");
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setRequestProperty("Authorization", "Bearer " + apiKey);
                conn.setRequestProperty("Accept", "application/json");
                String resp = readResponse(conn);
                SwingUtilities.invokeLater(() -> result.setText(formatJson(resp)));
            } catch (Exception ex) {
                SwingUtilities.invokeLater(() -> result.setText("Error: " + ex.getMessage()));
            }
        };

        usageBtn.addActionListener(e -> Executors.newSingleThreadExecutor().submit(loadUsage));
        billingBtn.addActionListener(e -> Executors.newSingleThreadExecutor().submit(loadBilling));
        Executors.newSingleThreadExecutor().submit(loadUsage);
        return panel;
    }

    private JPanel buildApiConsolePanel() {
        JPanel panel = new JPanel(new BorderLayout(0, 12));
        panel.setBackground(BG);
        panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));

        JLabel title = new JLabel("\u003E  API Console");
        title.setFont(new Font("Inter", Font.BOLD, 18));
        title.setForeground(TEXT);
        panel.add(title, BorderLayout.NORTH);

        JPanel inputPanel = new JPanel(new GridBagLayout());
        inputPanel.setBackground(BG);
        GridBagConstraints c = new GridBagConstraints();
        c.insets = new Insets(4, 4, 4, 4);
        c.fill = GridBagConstraints.HORIZONTAL;

        c.gridy = 0; c.gridx = 0;
        inputPanel.add(new JLabel("Method:"), c);
        JComboBox<String> methodBox = new JComboBox<>(new String[]{"GET", "POST", "PATCH", "DELETE"});
        methodBox.setBackground(SURFACE);
        methodBox.setForeground(TEXT);
        c.gridx = 1; inputPanel.add(methodBox, c);

        c.gridy = 0; c.gridx = 2;
        inputPanel.add(new JLabel("Endpoint:"), c);
        JTextField endpointField = new JTextField(25);
        styleField(endpointField);
        endpointField.setText("/jots/search?limit=5");
        c.gridx = 3; inputPanel.add(endpointField, c);

        c.gridy = 1; c.gridx = 0;
        inputPanel.add(new JLabel("Body:"), c);
        JTextArea bodyField = new JTextArea(3, 30);
        bodyField.setFont(new Font("Monospaced", Font.PLAIN, 12));
        bodyField.setBackground(SURFACE);
        bodyField.setForeground(TEXT);
        bodyField.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(BORDER),
            BorderFactory.createEmptyBorder(8, 10, 8, 10)));
        c.gridx = 1; c.gridwidth = 3; inputPanel.add(bodyField, c);

        JButton sendBtn = new JButton("Send Request");
        sendBtn.setFont(new Font("Inter", Font.BOLD, 14));
        sendBtn.setForeground(Color.WHITE);
        sendBtn.setBackground(ORANGE);
        sendBtn.setBorder(BorderFactory.createEmptyBorder(10, 24, 10, 24));
        sendBtn.setFocusPainted(false);
        c.gridy = 2; c.gridx = 0; c.gridwidth = 4; inputPanel.add(sendBtn, c);

        panel.add(inputPanel, BorderLayout.CENTER);

        JTextArea result = new JTextArea(10, 40);
        result.setFont(new Font("Monospaced", Font.PLAIN, 12));
        result.setBackground(SURFACE);
        result.setForeground(TEXT);
        result.setEditable(false);
        result.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(BORDER),
            BorderFactory.createEmptyBorder(10, 12, 10, 12)));
        panel.add(new JScrollPane(result), BorderLayout.SOUTH);

        sendBtn.addActionListener(e -> {
            sendBtn.setEnabled(false);
            sendBtn.setText("Sending...");
            String endpoint = endpointField.getText().trim();
            String method = (String) methodBox.getSelectedItem();
            String body = bodyField.getText().trim();

            Executors.newSingleThreadExecutor().submit(() -> {
                try {
                    URL url = new URL(apiBase + endpoint);
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    conn.setRequestMethod(method);
                    conn.setRequestProperty("Authorization", "Bearer " + apiKey);
                    conn.setRequestProperty("Accept", "application/json");
                    if (!body.isEmpty()) {
                        conn.setRequestProperty("Content-Type", "application/json");
                        conn.setDoOutput(true);
                        conn.getOutputStream().write(body.getBytes(StandardCharsets.UTF_8));
                    }
                    String resp = readResponse(conn);
                    int code = conn.getResponseCode();
                    String finalResp = resp;
                    SwingUtilities.invokeLater(() -> {
                        result.setText("HTTP " + code + "\n" + formatJson(finalResp));
                        sendBtn.setEnabled(true);
                        sendBtn.setText("Send Request");
                    });
                } catch (Exception ex) {
                    SwingUtilities.invokeLater(() -> {
                        result.setText("Error: " + ex.getMessage());
                        sendBtn.setEnabled(true);
                        sendBtn.setText("Send Request");
                    });
                }
            });
        });
        return panel;
    }

    private void showActivation() {
        cardLayout.show(mainPanel, "panelActivation");
    }

    private void logout() {
        apiKey = "";
        keyLabel.setText("");
        statusLabel.setText("Locked");
        statusLabel.setForeground(DIM);
        showActivation();
    }

    private void styleField(JTextField field) {
        field.setFont(new Font("Inter", Font.PLAIN, 13));
        field.setBackground(SURFACE);
        field.setForeground(TEXT);
        field.setCaretColor(ORANGE);
        field.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(BORDER),
            BorderFactory.createEmptyBorder(8, 10, 8, 10)));
    }

    private void styleBtn(JButton btn) {
        btn.setFont(new Font("Inter", Font.BOLD, 14));
        btn.setForeground(Color.WHITE);
        btn.setBackground(ORANGE);
        btn.setBorder(BorderFactory.createEmptyBorder(10, 24, 10, 24));
        btn.setFocusPainted(false);
    }

    private String readResponse(HttpURLConnection conn) throws IOException {
        int code = conn.getResponseCode();
        InputStream is = (code >= 200 && code < 300) ? conn.getInputStream() : conn.getErrorStream();
        if (is == null) return "HTTP " + code + " (no body)";
        String body = new String(is.readAllBytes(), StandardCharsets.UTF_8);
        return body;
    }

    private String formatJson(String json) {
        try {
            int indent = 0;
            StringBuilder sb = new StringBuilder();
            boolean inString = false;
            for (char c : json.toCharArray()) {
                if (c == '\"') inString = !inString;
                if (!inString && (c == '{' || c == '[')) {
                    sb.append(c).append('\n');
                    indent += 2;
                    sb.append(" ".repeat(indent));
                } else if (!inString && (c == '}' || c == ']')) {
                    sb.append('\n');
                    indent -= 2;
                    sb.append(" ".repeat(indent)).append(c);
                } else if (!inString && c == ',') {
                    sb.append(c).append('\n');
                    sb.append(" ".repeat(indent));
                } else if (!inString && c == ':') {
                    sb.append(": ");
                } else {
                    sb.append(c);
                }
            }
            return sb.toString();
        } catch (Exception e) {
            return json;
        }
    }

    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception e) {}
        SwingUtilities.invokeLater(() -> new CallJotsDesktop().setVisible(true));
    }
}