package cz.kamma.kfmanager.ui;

import cz.kamma.kfmanager.model.FileItem;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.io.File;
import java.util.List;

/**
 * File panel with tab support
 */
public class FilePanel extends JPanel {
    
    private JTabbedPane tabbedPane;
    private JComboBox<File> driveCombo;
    private JLabel driveInfoLabel;
    private cz.kamma.kfmanager.config.AppConfig appConfig;
    private Runnable onDirectoryChangedAll;
    
    public FilePanel(String initialPath) {
        initComponents();
        addNewTab(initialPath, false);
    }

    public void setOnDirectoryChangedAll(Runnable callback) {
        this.onDirectoryChangedAll = callback;
    }

    /** Start inline rename on the currently selected tab/table. */
    public void startInlineRename() {
        FilePanelTab tab = getCurrentTab();
        if (tab != null) tab.startInlineRename();
    }

    /** Select files by wildcard pattern in the current tab. */
    public void selectByWildcard(String pattern) {
        FilePanelTab tab = getCurrentTab();
        if (tab != null) tab.selectByWildcard(pattern);
    }

    private Runnable switchPanelCallback;

    public void setSwitchPanelCallback(Runnable cb) {
        this.switchPanelCallback = cb;
    }
    
    private void initComponents() {
        tabbedPane = new JTabbedPane();
        setLayout(new BorderLayout());
        setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        
    // Top panel with path field
        JPanel topPanel = new JPanel(new BorderLayout());

        // Drive selection dropdown placed before the path field
    driveCombo = new JComboBox<>();
    // Return focus to table when ESC is pressed in the combo
    driveCombo.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "cancel-drive-selection");
    driveCombo.getActionMap().put("cancel-drive-selection", new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent e) {
            driveCombo.hidePopup();
            FilePanelTab tab = getCurrentTab();
            if (tab != null) tab.getFileTable().requestFocusInWindow();
        }
    });
    // Allow the combo to receive focus so keyboard navigation and popup interaction work
    driveCombo.setFocusable(true);
        driveCombo.setToolTipText("Select drive");
        // renderer to show friendly name and path
        driveCombo.setRenderer(new DefaultListCellRenderer() {
            private final javax.swing.filechooser.FileSystemView fsv = javax.swing.filechooser.FileSystemView.getFileSystemView();
            @Override
            public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
                super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
                if (value instanceof File) {
                    File f = (File) value;
                    String name = fsv.getSystemDisplayName(f);
                    if (name == null) name = "";
                    name = name.trim();
                    // Strip surrounding parentheses if present (e.g. "(C)")
                    if (name.startsWith("(") && name.endsWith(")") && name.length() > 1) {
                        name = name.substring(1, name.length() - 1).trim();
                    }
                    String path = f.getAbsolutePath();
                    String driveLabel;
                    // Prefer Windows-style drive letter like "C:" when available
                    if (path != null && path.length() >= 2 && path.charAt(1) == ':') {
                        driveLabel = path.substring(0, 2);
                    } else {
                        // Fall back to path or empty
                        driveLabel = path != null ? path : "";
                    }
                    // Remove redundant drive-letter fragments from name (e.g. "C", "C:", "(C)")
                    if (!driveLabel.isEmpty() && !name.isEmpty()) {
                        // remove occurrences of driveLabel or driveLabel + ':' and stray parentheses
                        name = name.replace(driveLabel, "").replace(driveLabel + ":", "").replace("(", "").replace(")", "").trim();
                    }
                    String text = driveLabel;
                    if (!name.isEmpty()) text = text + " " + name;
                    setText(text);
                }
                return this;
            }
    });

    // Small label next to the combo to show drive info (label, capacity, free space)
        driveInfoLabel = new JLabel();
        driveInfoLabel.setFont(new Font("SansSerif", Font.PLAIN, 12));
        driveInfoLabel.setBorder(BorderFactory.createEmptyBorder(0,6,0,6));

        // Require explicit confirmation (Enter) to load selected drive.
        // Selection changes (mouse/typing) only update the selected item; loading occurs on Enter.
        driveCombo.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_ENTER, 0), "confirmDrive");
        driveCombo.getActionMap().put("confirmDrive", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                Object selObj = driveCombo.getSelectedItem();
                if (selObj instanceof File) {
                    File sel = (File) selObj;
                    FilePanelTab currentTab = getCurrentTab();
                    if (currentTab != null) {
                        currentTab.loadDirectory(sel);
                        SwingUtilities.invokeLater(() -> {
                            try { currentTab.getFileTable().requestFocusInWindow(); } catch (Exception ignore) {}
                        });
                    }
                }
            }
        });
        // Compose a small left panel with the combo and info label
        JPanel leftPanel = new JPanel();
        leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.X_AXIS));
        leftPanel.add(driveCombo);
        leftPanel.add(driveInfoLabel);
    topPanel.add(leftPanel, BorderLayout.WEST);
    // Populate drives after the info label is created so updateDriveInfo() can safely access it
    populateDrives();

    // Path field removed; path is shown in tab titles instead
        
    // Buttons for navigation
    JPanel navBtnPaths = new JPanel(new FlowLayout(FlowLayout.RIGHT, 2, 0));
    JButton homeButton = new JButton("~");
    homeButton.setToolTipText("Home Directory");
    homeButton.addActionListener(e -> {
        FilePanelTab currentTab = getCurrentTab();
        if (currentTab != null) {
            currentTab.loadDirectory(new File(System.getProperty("user.home")));
        }
    });

    JButton upButton = new JButton("↑");
    upButton.setToolTipText("Parent directory (Backspace)");
        upButton.addActionListener(e -> {
            FilePanelTab currentTab = getCurrentTab();
            if (currentTab != null) {
                currentTab.navigateUp();
            }
        });
        navBtnPaths.add(homeButton);
        navBtnPaths.add(upButton);
        topPanel.add(navBtnPaths, BorderLayout.EAST);
        
        add(topPanel, BorderLayout.NORTH);
        
        // JTabbedPane for tabs
        tabbedPane.setTabPlacement(JTabbedPane.TOP);
        
        // Listener for updating path and style on tab change
        tabbedPane.addChangeListener(e -> {
            updatePathField();
            updateTabStyles();
        });
        
        add(tabbedPane, BorderLayout.CENTER);

        // Click on panel background or empty areas should focus the table
        addMouseListenerToComponents(this);
    }

    /**
     * Recursively adds a mouse listener to all components (except buttons/combos)
     * to request focus for the active table when clicked.
     */
    private void addMouseListenerToComponents(Component comp) {
        if (comp == null) return;
        
        // Components that should NOT steal focus back to the table when clicked
        boolean isInteractive = comp instanceof JButton || 
                                comp instanceof JComboBox || 
                                comp instanceof JTextField || 
                                comp instanceof JTable;
                                
        if (!isInteractive) {
            comp.addMouseListener(new java.awt.event.MouseAdapter() {
                @Override
                public void mousePressed(java.awt.event.MouseEvent e) {
                    FilePanelTab tab = getCurrentTab();
                    if (tab != null) {
                        tab.getFileTable().requestFocusInWindow();
                        tab.selectLastItem();
                    }
                }
            });
        }
        
        if (comp instanceof Container) {
            for (Component child : ((Container) comp).getComponents()) {
                addMouseListenerToComponents(child);
            }
        }
    }

    /**
     * Show the drive dropdown popup and focus it.
     */
    public void showDrivePopup() {
        if (driveCombo == null) return;
        SwingUtilities.invokeLater(() -> {
            try {
                driveCombo.requestFocusInWindow();
                driveCombo.showPopup();
            } catch (Exception ignore) {}
        });
    }
    
    /**
     * Add a new tab with a directory
     */
    public void addNewTab(String path) {
        addNewTab(path, true);
    }

    public void addNewTab(String path, boolean requestFocus) {
        // Get view mode from current tab
        ViewMode currentMode = getViewMode();
        
        FilePanelTab tab = new FilePanelTab(path, requestFocus);
        if (appConfig != null) tab.setAppConfig(appConfig);
        
        // Set callback for updating tab title on directory change
        tab.setOnDirectoryChanged(() -> {
            updateTabTitle(tab);
            if (onDirectoryChangedAll != null) onDirectoryChangedAll.run();
        });

        // Forward switchPanel callback to the tab so TAB works from any tab
        tab.setOnSwitchPanelRequested(switchPanelCallback);
        
        // Set same view mode as current tab
        if (currentMode != null) {
            tab.setViewMode(currentMode);
        }
        
        String tabTitle = getTabTitle(path);
        
        tabbedPane.addTab(tabTitle, tab);
        tabbedPane.setSelectedComponent(tab);
        
        // Ensure clicking on empty areas of the tab/scrollpane focuses the table
        addMouseListenerToComponents(tab);
        
        // Update path field
        updateTabStyles();
        
        // Set focus to the table in the new tab
        SwingUtilities.invokeLater(() -> {
            if (requestFocus) {
                tab.getFileTable().requestFocusInWindow();
            }
            // Ensure renderers are attached now that the tab is added to the UI
            tab.ensureRenderers();
        });
    }

    /**
     * Add a new tab and explicitly set the ViewMode for this tab.
     */
    public void addNewTabWithMode(String path, ViewMode mode) {
        addNewTabWithMode(path, mode, true);
    }

    public void addNewTabWithMode(String path, ViewMode mode, boolean requestFocus) {
        FilePanelTab tab = new FilePanelTab(path, requestFocus);
        if (appConfig != null) tab.setAppConfig(appConfig);
        tab.setOnDirectoryChanged(() -> {
            updateTabTitle(tab);
            if (onDirectoryChangedAll != null) onDirectoryChangedAll.run();
        });
        tab.setOnSwitchPanelRequested(switchPanelCallback);

        if (mode != null) {
            tab.setViewMode(mode);
        }

        String tabTitle = getTabTitle(path);
        tabbedPane.addTab(tabTitle, tab);
        tabbedPane.setSelectedComponent(tab);

        // Ensure clicking on empty areas of the tab/scrollpane focuses the table
        addMouseListenerToComponents(tab);

        updatePathField();
        updateTabStyles();

        SwingUtilities.invokeLater(() -> {
            if (requestFocus) {
                tab.getFileTable().requestFocusInWindow();
            }
            tab.ensureRenderers();
        });
    }

    /**
     * Provide AppConfig so tabs can persist/retrieve sort settings
     */
    public void setAppConfig(cz.kamma.kfmanager.config.AppConfig cfg) {
        this.appConfig = cfg;
        // propagate to existing tabs
        for (int i = 0; i < tabbedPane.getTabCount(); i++) {
            Component c = tabbedPane.getComponentAt(i);
            if (c instanceof FilePanelTab) {
                ((FilePanelTab) c).setAppConfig(cfg);
            }
        }
    }

    public java.util.List<String> getTabPaths() {
        java.util.List<String> paths = new java.util.ArrayList<>();
        for (int i = 0; i < tabbedPane.getTabCount(); i++) {
            Component c = tabbedPane.getComponentAt(i);
            if (c instanceof FilePanelTab) {
                FilePanelTab t = (FilePanelTab) c;
                File dir = t.getCurrentDirectory();
                paths.add(dir != null ? dir.getAbsolutePath() : System.getProperty("user.home"));
            }
        }
        return paths;
    }

    public java.util.List<String> getTabViewModes() {
        java.util.List<String> modes = new java.util.ArrayList<>();
        for (int i = 0; i < tabbedPane.getTabCount(); i++) {
            Component c = tabbedPane.getComponentAt(i);
            if (c instanceof FilePanelTab) {
                FilePanelTab t = (FilePanelTab) c;
                modes.add(t.getViewMode() != null ? t.getViewMode().name() : ViewMode.FULL.name());
            }
        }
        return modes;
    }

    public java.util.List<String> getTabFocusedItems() {
        java.util.List<String> items = new java.util.ArrayList<>();
        for (int i = 0; i < tabbedPane.getTabCount(); i++) {
            Component c = tabbedPane.getComponentAt(i);
            if (c instanceof FilePanelTab) {
                cz.kamma.kfmanager.model.FileItem focused = ((FilePanelTab) c).getFocusedItem();
                items.add(focused != null ? focused.getName() : null);
            }
        }
        return items;
    }

    public int getSelectedTabIndex() {
        return tabbedPane.getSelectedIndex();
    }

    /**
     * Restore the set of tabs according to specified paths and view modes. If the list is empty, nothing happens.
     */
    public void restoreTabs(java.util.List<String> paths, java.util.List<String> viewModes, java.util.List<String> focusedItems, int selectedIndex) {
        restoreTabs(paths, viewModes, focusedItems, selectedIndex, true);
    }

    public void restoreTabs(java.util.List<String> paths, java.util.List<String> viewModes, java.util.List<String> focusedItems, int selectedIndex, boolean requestFocus) {
        if (paths == null || paths.isEmpty()) return;

        tabbedPane.removeAll();

        for (int i = 0; i < paths.size(); i++) {
            String p = paths.get(i);
            ViewMode mode = ViewMode.FULL;
            if (viewModes != null && i < viewModes.size()) {
                try {
                    mode = ViewMode.valueOf(viewModes.get(i));
                } catch (IllegalArgumentException ex) {
                    mode = ViewMode.FULL;
                }
            }
            addNewTabWithMode(p, mode, false);

            // Restore focus to the specific item if provided
            if (focusedItems != null && i < focusedItems.size() && focusedItems.get(i) != null) {
                final String focusName = focusedItems.get(i);
                final FilePanelTab currentTab = (FilePanelTab) tabbedPane.getComponentAt(i);
                SwingUtilities.invokeLater(() -> currentTab.selectItem(focusName, requestFocus));
            }
        }

        if (selectedIndex >= 0 && selectedIndex < tabbedPane.getTabCount()) {
            tabbedPane.setSelectedIndex(selectedIndex);
        } else if (tabbedPane.getTabCount() > 0) {
            tabbedPane.setSelectedIndex(0);
        }

        updatePathField();
        updateTabStyles();
    }

    private void populateDrives() {
        driveCombo.removeAllItems();
        java.util.Set<File> driveSet = new java.util.LinkedHashSet<>();
        
        // Add standard roots
        File[] roots = File.listRoots();
        if (roots != null) {
            for (File r : roots) {
                driveSet.add(r);
            }
        }
        
        // Add home directory
        driveSet.add(new File(System.getProperty("user.home")));
        
        // On Linux/Unix, add common mount points
        String os = System.getProperty("os.name").toLowerCase();
        if (!os.contains("win")) {
            // Common Linux/Unix mount points
            String user = System.getProperty("user.name");
            
            // Typical locations for removable media
            String[] commonMountPoints = {
                "/media/" + user,
                "/run/media/" + user,
                "/mnt",
                "/Volumes" // macOS
            };
            
            for (String path : commonMountPoints) {
                File dir = new File(path);
                if (dir.exists() && dir.isDirectory()) {
                    File[] subDirs = dir.listFiles();
                    if (subDirs != null) {
                        for (File sub : subDirs) {
                            if (sub.isDirectory()) {
                                driveSet.add(sub);
                            }
                        }
                    } else if (!path.contains(user)) {
                        // For /mnt we might also add the directory itself if it's empty but meant to be used
                        driveSet.add(dir);
                    }
                }
            }
        }
        
        for (File d : driveSet) {
            try {
                driveCombo.addItem(d);
            } catch (Exception ignore) {}
        }

        // Initialize selection
        if (driveCombo.getItemCount() > 0) {
            driveCombo.setSelectedIndex(0);
        }

        // Update info for currently selected drive
        updateDriveInfoFromSelection();

        // Update info label on selection changes (visual selection only)
        driveCombo.addItemListener(ev -> {
            if (ev.getStateChange() == java.awt.event.ItemEvent.SELECTED) {
                updateDriveInfoFromSelection();
            }
        });
    }
    
    /**
     * Get tab title from path
     */
    private String getTabTitle(String path) {
        String tabTitle = new File(path).getName();
        if (tabTitle.isEmpty()) {
            tabTitle = path; // For root paths like "C:\"
        }
        return tabTitle;
    }
    
    /**
     * Update the title of a tab according to its current directory
     */
    private void updateTabTitle(FilePanelTab tab) {
        updateTabStyles();
    }

    /**
     * Set the active state of this panel to show/hide the focus indicator strip.
     * The indicator is placed between the drive dropdown and the tabs.
     */
    public void setActive(boolean active, Color activeColor) {
        // Inactive indicator is subtle dark gray
        Color inactiveColor = new Color(60, 60, 60);
        Color targetColor = active ? activeColor : inactiveColor;
        
        // Apply a matte border to the top of tabbedPane - this places it between 
        // the topPanel (dropdown) and the tabs themselves.
        tabbedPane.setBorder(BorderFactory.createMatteBorder(3, 0, 0, 0, targetColor));
        revalidate();
        repaint();
    }

    /**
     * Updates tab style - highlights the active tab with bold font and color.
     */
    private void updateTabStyles() {
        if (tabbedPane == null) return;
        int selectedIndex = tabbedPane.getSelectedIndex();
        for (int i = 0; i < tabbedPane.getTabCount(); i++) {
            Component c = tabbedPane.getComponentAt(i);
            if (c instanceof FilePanelTab) {
                FilePanelTab tab = (FilePanelTab) c;
                File dir = tab.getCurrentDirectory();
                String title = getTabTitle(dir != null ? dir.getAbsolutePath() : "");
                
                if (i == selectedIndex) {
                    // Active tab: bold font and dark blue color
                    tabbedPane.setTitleAt(i, "<html><b>" + title + "</b></html>");
                    tabbedPane.setForegroundAt(i, new Color(0, 51, 153));
                } else {
                    // Inactive tab: normal font and default color
                    tabbedPane.setTitleAt(i, title);
                    tabbedPane.setForegroundAt(i, null);
                }
            }
        }
    }
    
    /**
     * Remove the current tab
     */
    public void closeCurrentTab() {
        int index = tabbedPane.getSelectedIndex();
        if (index >= 0 && tabbedPane.getTabCount() > 1) {
            tabbedPane.removeTabAt(index);
            updatePathField();
            updateTabStyles();
            
            // Set focus to the table in the newly active tab
            FilePanelTab currentTab = getCurrentTab();
            if (currentTab != null) {
                SwingUtilities.invokeLater(() -> currentTab.getFileTable().requestFocusInWindow());
            }
        }
    }
    
    /**
     * Return the current active tab
     */
    public FilePanelTab getCurrentTab() {
        int index = tabbedPane.getSelectedIndex();
        if (index >= 0) {
            return (FilePanelTab) tabbedPane.getComponentAt(index);
        }
        return null;
    }
    
    /**
     * Update path field based on current tab
     */
    private void updatePathField() {
        FilePanelTab currentTab = getCurrentTab();
        if (currentTab != null) {
            // Update drive combo selection to match current directory
            try {
                File cur = currentTab.getCurrentDirectory();
                if (cur != null) {
                    File root = cur.toPath().getRoot().toFile();
                    driveCombo.setSelectedItem(root);
                    // also update info label to reflect current tab's root
                    updateDriveInfo(root);
                }
            } catch (Exception ignore) {}
        }
    }

    private void updateDriveInfoFromSelection() {
        Object sel = driveCombo.getSelectedItem();
        if (sel instanceof File) {
            updateDriveInfo((File) sel);
        } else {
            driveInfoLabel.setText("");
        }
    }

    private void updateDriveInfo(File drive) {
        try {
            javax.swing.filechooser.FileSystemView fsv = javax.swing.filechooser.FileSystemView.getFileSystemView();
            String name = fsv.getSystemDisplayName(drive);
            if (name == null) name = "";
            name = name.trim();
            // strip surrounding parentheses left by some platform names
            if (name.startsWith("(") && name.endsWith(")") && name.length() > 1) {
                name = name.substring(1, name.length() - 1).trim();
            }
            if (name.isEmpty()) {
                // fallback to drive letter like "C:"
                String path = drive != null ? drive.getAbsolutePath() : "";
                if (path != null && path.length() >= 2 && path.charAt(1) == ':') {
                    name = path.substring(0, 2);
                } else {
                    name = path != null ? path : "";
                }
            }
            long total = drive.getTotalSpace();
            long free = drive.getUsableSpace();
            String freeGb = formatGbShort(free);
            String totalGb = formatGbShort(total);
            String info = String.format("%s %s GB free of %s GB", name, freeGb, totalGb);
            driveInfoLabel.setText(info);
        } catch (Exception ex) {
            driveInfoLabel.setText("");
        }
    }

    private static String formatGbShort(long bytes) {
        if (bytes <= 0) return "0"; // fallback
        double gb = bytes / 1024.0 / 1024.0 / 1024.0;
        return String.format("%.1f", gb);
    }
    
    /**
     * Request focus on the table in the current tab
     */
    public void requestFocusOnCurrentTab() {
        FilePanelTab currentTab = getCurrentTab();
        if (currentTab != null) {
            currentTab.getFileTable().requestFocusInWindow();
        }
    }
    
    // Delegation of methods to current tab

    /**
     * Switch to the next tab in this panel.
     */
    public void nextTab() {
        int count = tabbedPane.getTabCount();
        if (count > 1) {
            int nextIndex = (tabbedPane.getSelectedIndex() + 1) % count;
            tabbedPane.setSelectedIndex(nextIndex);
            FilePanelTab tab = getCurrentTab();
            if (tab != null) {
                tab.getFileTable().requestFocusInWindow();
            }
        }
    }
    
    public JTable getFileTable() {
        FilePanelTab tab = getCurrentTab();
        return tab != null ? tab.getFileTable() : null;
    }
    
    public File getCurrentDirectory() {
        FilePanelTab tab = getCurrentTab();
        return tab != null ? tab.getCurrentDirectory() : null;
    }

    public String getCurrentPath() {
        File dir = getCurrentDirectory();
        return dir != null ? dir.getAbsolutePath() : "";
    }
    
    public List<FileItem> getSelectedItems() {
        FilePanelTab tab = getCurrentTab();
        return tab != null ? tab.getSelectedItems() : java.util.Collections.emptyList();
    }

    public FileItem getFocusedItem() {
        FilePanelTab tab = getCurrentTab();
        return tab != null ? tab.getFocusedItem() : null;
    }
    
    public void setViewMode(ViewMode mode) {
        setViewMode(mode, true);
    }

    public void setViewMode(ViewMode mode, boolean requestFocus) {
        FilePanelTab tab = getCurrentTab();
        if (tab != null) {
            tab.setViewMode(mode, requestFocus);
        }
    }
    
    public ViewMode getViewMode() {
        FilePanelTab tab = getCurrentTab();
        return tab != null ? tab.getViewMode() : ViewMode.FULL;
    }
    
    public void loadDirectory(File directory) {
        loadDirectory(directory, true);
    }

    public void loadDirectory(File directory, boolean requestFocus) {
        loadDirectory(directory, true, requestFocus);
    }

    public void loadDirectory(File directory, boolean autoSelectFirst, boolean requestFocus) {
        FilePanelTab tab = getCurrentTab();
        if (tab != null) {
            tab.loadDirectory(directory, autoSelectFirst, requestFocus);
            updatePathField();
        }
    }
    
    public void toggleSelectionAndMoveDown() {
        FilePanelTab tab = getCurrentTab();
        if (tab != null) {
            tab.toggleSelectionAndMoveDown();
        }
    }

    // --- Appearance application helpers ---
    public void applyGlobalFont(Font font) {
        // Apply to all existing tabs
        for (int i = 0; i < tabbedPane.getTabCount(); i++) {
            Component c = tabbedPane.getComponentAt(i);
            if (c instanceof FilePanelTab) {
                ((FilePanelTab) c).applyGlobalFont(font);
            }
        }
    }

    public void applyBackgroundColor(Color bg) {
        if (bg == null) return;
        updateComponentBackground(this, bg);
        for (int i = 0; i < tabbedPane.getTabCount(); i++) {
            Component c = tabbedPane.getComponentAt(i);
            if (c instanceof FilePanelTab) {
                ((FilePanelTab) c).applyBackgroundColor(bg);
            }
        }
    }

    private void updateComponentBackground(Container container, Color bg) {
        if (container == null) return;
        container.setBackground(bg);
        boolean dark = isDark(bg);
        for (Component c : container.getComponents()) {
            if (c instanceof JPanel || c instanceof JToolBar || c instanceof JScrollPane || c instanceof JViewport || c instanceof JTabbedPane || c instanceof JButton) {
                c.setBackground(bg);
            }
            if (c instanceof JLabel || c instanceof JCheckBox || c instanceof JRadioButton || c instanceof JButton) {
                c.setForeground(dark ? Color.WHITE : Color.BLACK);
            }
            if (c instanceof Container) {
                updateComponentBackground((Container) c, bg);
            }
        }
    }

    private boolean isDark(Color c) {
        if (c == null) return false;
        double darkness = 1 - (0.299 * c.getRed() + 0.587 * c.getGreen() + 0.114 * c.getBlue()) / 255;
        return darkness >= 0.5;
    }

    public void applySelectionColor(Color sel) {
        for (int i = 0; i < tabbedPane.getTabCount(); i++) {
            Component c = tabbedPane.getComponentAt(i);
            if (c instanceof FilePanelTab) {
                ((FilePanelTab) c).applySelectionColor(sel);
            }
        }
    }

    public void applyMarkedColor(Color mark) {
        for (int i = 0; i < tabbedPane.getTabCount(); i++) {
            Component c = tabbedPane.getComponentAt(i);
            if (c instanceof FilePanelTab) {
                ((FilePanelTab) c).applyMarkedColor(mark);
            }
        }
    }
}
