package cz.kamma.kfmanager.config;

import java.awt.*;
import java.io.*;
import java.util.Properties;

/**
 * Class for saving and loading the application configuration
 */
public class AppConfig {
    
    private static final String CONFIG_FILE = System.getProperty("user.home") + 
            File.separator + ".kfmanager" + File.separator + "config.properties";
    
    private Properties properties;
    
    public AppConfig() {
        properties = new Properties();
        loadConfig();
    }
    
    /**
     * Load configuration from file
     */
    private void loadConfig() {
        File configFile = new File(CONFIG_FILE);
        if (configFile.exists()) {
            try (FileInputStream fis = new FileInputStream(configFile)) {
                properties.load(fis);
            } catch (IOException e) {
                System.err.println("Could not load configuration: " + e.getMessage());
            }
        }
    }
    
    /**
     * Save configuration to file
     */
    public void saveConfig() {
        File configFile = new File(CONFIG_FILE);
        File configDir = configFile.getParentFile();
        
    // Create configuration directory if it does not exist
        if (!configDir.exists()) {
            configDir.mkdirs();
        }
        
        try (FileOutputStream fos = new FileOutputStream(configFile)) {
            properties.store(fos, "KF File Manager Configuration");
        } catch (IOException e) {
            System.err.println("Could not save configuration: " + e.getMessage());
        }
    }
    
    // Getters and setters for individual configuration values
    
    public int getWindowX() {
        return Integer.parseInt(properties.getProperty("window.x", "100"));
    }
    
    public void setWindowX(int x) {
        properties.setProperty("window.x", String.valueOf(x));
    }
    
    public int getWindowY() {
        return Integer.parseInt(properties.getProperty("window.y", "100"));
    }
    
    public void setWindowY(int y) {
        properties.setProperty("window.y", String.valueOf(y));
    }
    
    public int getWindowWidth() {
        return Integer.parseInt(properties.getProperty("window.width", "1200"));
    }
    
    public void setWindowWidth(int width) {
        properties.setProperty("window.width", String.valueOf(width));
    }
    
    public int getWindowHeight() {
        return Integer.parseInt(properties.getProperty("window.height", "700"));
    }
    
    public void setWindowHeight(int height) {
        properties.setProperty("window.height", String.valueOf(height));
    }
    
    public boolean isWindowMaximized() {
        return Boolean.parseBoolean(properties.getProperty("window.maximized", "false"));
    }
    
    public void setWindowMaximized(boolean maximized) {
        properties.setProperty("window.maximized", String.valueOf(maximized));
    }

    public String getActivePanel() {
        return properties.getProperty("active.panel", "left");
    }

    public void setActivePanel(String panel) {
        properties.setProperty("active.panel", panel);
    }

    public int getBriefMouseWheelSteps() {
        try {
            return Integer.parseInt(properties.getProperty("brief.mousewheel.steps", "10"));
        } catch (NumberFormatException e) {
            return 10;
        }
    }

    public void setBriefMouseWheelSteps(int steps) {
        properties.setProperty("brief.mousewheel.steps", String.valueOf(steps));
    }
    
    public String getLeftPanelPath() {
        return properties.getProperty("leftPanel.path", System.getProperty("user.home"));
    }
    
    public void setLeftPanelPath(String path) {
        properties.setProperty("leftPanel.path", path);
    }
    
    public String getRightPanelPath() {
        return properties.getProperty("rightPanel.path", System.getProperty("user.home"));
    }
    
    public void setRightPanelPath(String path) {
        properties.setProperty("rightPanel.path", path);
    }
    
    // ViewMode configuration
    public String getLeftPanelViewMode() {
        return properties.getProperty("leftPanel.viewMode", "FULL");
    }
    
    public void setLeftPanelViewMode(String viewMode) {
        properties.setProperty("leftPanel.viewMode", viewMode);
    }
    
    public String getRightPanelViewMode() {
        return properties.getProperty("rightPanel.viewMode", "FULL");
    }
    
    public void setRightPanelViewMode(String viewMode) {
        properties.setProperty("rightPanel.viewMode", viewMode);
    }

    // --- Tab/session persistence ---
    public int getLeftPanelTabCount() {
        return Integer.parseInt(properties.getProperty("leftPanel.tabs.count", "0"));
    }

    public String getLeftPanelTabPath(int index) {
        return properties.getProperty("leftPanel.tab." + index + ".path", null);
    }

    public String getLeftPanelTabFocusedItem(int index) {
        return properties.getProperty("leftPanel.tab." + index + ".focusedItem", null);
    }

    public String getLeftPanelTabViewMode(int index) {
        return properties.getProperty("leftPanel.tab." + index + ".viewMode", "FULL");
    }

    public int getLeftPanelSelectedIndex() {
        return Integer.parseInt(properties.getProperty("leftPanel.selectedIndex", "0"));
    }

    public void saveLeftPanelTabs(java.util.List<String> paths, java.util.List<String> viewModes, java.util.List<String> focusedItems, int selectedIndex) {
        properties.setProperty("leftPanel.tabs.count", String.valueOf(paths.size()));
        for (int i = 0; i < paths.size(); i++) {
            properties.setProperty("leftPanel.tab." + i + ".path", paths.get(i));
            properties.setProperty("leftPanel.tab." + i + ".viewMode", viewModes.get(i));
            if (focusedItems != null && i < focusedItems.size() && focusedItems.get(i) != null) {
                properties.setProperty("leftPanel.tab." + i + ".focusedItem", focusedItems.get(i));
            } else {
                properties.remove("leftPanel.tab." + i + ".focusedItem");
            }
        }
        properties.setProperty("leftPanel.selectedIndex", String.valueOf(selectedIndex));
    }

    public int getRightPanelTabCount() {
        return Integer.parseInt(properties.getProperty("rightPanel.tabs.count", "0"));
    }

    public String getRightPanelTabFocusedItem(int index) {
        return properties.getProperty("rightPanel.tab." + index + ".focusedItem", null);
    }

    public String getRightPanelTabPath(int index) {
        return properties.getProperty("rightPanel.tab." + index + ".path", null);
    }

    public String getRightPanelTabViewMode(int index) {
        return properties.getProperty("rightPanel.tab." + index + ".viewMode", "FULL");
    }

    public int getRightPanelSelectedIndex() {
        return Integer.parseInt(properties.getProperty("rightPanel.selectedIndex", "0"));
    }

    public void saveRightPanelTabs(java.util.List<String> paths, java.util.List<String> viewModes, java.util.List<String> focusedItems, int selectedIndex) {
        properties.setProperty("rightPanel.tabs.count", String.valueOf(paths.size()));
        for (int i = 0; i < paths.size(); i++) {
            properties.setProperty("rightPanel.tab." + i + ".path", paths.get(i));
            properties.setProperty("rightPanel.tab." + i + ".viewMode", viewModes.get(i));
            if (focusedItems != null && i < focusedItems.size() && focusedItems.get(i) != null) {
                properties.setProperty("rightPanel.tab." + i + ".focusedItem", focusedItems.get(i));
            } else {
                properties.remove("rightPanel.tab." + i + ".focusedItem");
            }
        }
        properties.setProperty("rightPanel.selectedIndex", String.valueOf(selectedIndex));
    }
    
    // Font configuration
    public String getEditorFontName() {
        return properties.getProperty("editor.font.name", "Monospaced");
    }
    
    public void setEditorFontName(String fontName) {
        properties.setProperty("editor.font.name", fontName);
    }
    
    public int getEditorFontSize() {
        return Integer.parseInt(properties.getProperty("editor.font.size", "12"));
    }
    
    public void setEditorFontSize(int fontSize) {
        properties.setProperty("editor.font.size", String.valueOf(fontSize));
    }

    public int getEditorFontStyle() {
        return Integer.parseInt(properties.getProperty("editor.font.style", String.valueOf(Font.PLAIN)));
    }

    public void setEditorFontStyle(int style) {
        properties.setProperty("editor.font.style", String.valueOf(style));
    }
    
    public Font getEditorFont() {
        return new Font(getEditorFontName(), getEditorFontStyle(), getEditorFontSize());
    }
    
    public void setEditorFont(Font font) {
        setEditorFontName(font.getName());
        setEditorFontSize(font.getSize());
        setEditorFontStyle(font.getStyle());
    }

    // Toolbar configuration
    public int getToolbarButtonSize() {
        return Integer.parseInt(properties.getProperty("toolbar.button.size", "30"));
    }
    
    public void setToolbarButtonSize(int size) {
        properties.setProperty("toolbar.button.size", String.valueOf(size));
    }
    
    public int getToolbarIconSize() {
        return Integer.parseInt(properties.getProperty("toolbar.icon.size", "24"));
    }
    
    public void setToolbarIconSize(int size) {
        properties.setProperty("toolbar.icon.size", String.valueOf(size));
    }

    // --- External editor configuration ---
    /** Path to external editor binary (empty = use internal editor) */
    public String getExternalEditorPath() {
        return properties.getProperty("editor.external.path", "");
    }

    public void setExternalEditorPath(String path) {
        if (path == null || path.isEmpty()) {
            properties.remove("editor.external.path");
        } else {
            properties.setProperty("editor.external.path", path);
        }
    }

    // --- File Associations ---
    /** Returns a map of pattern (extension or wildcard) -> command */
    public java.util.Map<String, String> getFileAssociations() {
        java.util.Map<String, String> map = new java.util.HashMap<>();
        for (String key : properties.stringPropertyNames()) {
            if (key.startsWith("assoc.")) {
                String pattern = key.substring(6);
                map.put(pattern, properties.getProperty(key));
            }
        }
        return map;
    }

    public void setFileAssociations(java.util.Map<String, String> associations) {
        // Remove all current associations first
        for (String key : properties.stringPropertyNames()) {
            if (key.startsWith("assoc.")) {
                properties.remove(key);
            }
        }
        // Add new ones
        if (associations != null) {
            for (java.util.Map.Entry<String, String> entry : associations.entrySet()) {
                String pattern = entry.getKey().trim();
                if (!pattern.isEmpty()) {
                    properties.setProperty("assoc." + pattern, entry.getValue());
                }
            }
        }
    }

    /** Add or update a single file association */
    public void setFileAssociation(String pattern, String command) {
        if (pattern == null || pattern.trim().isEmpty()) return;
        properties.setProperty("assoc." + pattern.trim(), command);
        saveConfig();
    }

    // --- Appearance (global) settings ---
    public String getGlobalFontName() {
        return properties.getProperty("global.font.name", "Monospaced");
    }

    public void setGlobalFontName(String name) {
        properties.setProperty("global.font.name", name);
    }

    public int getGlobalFontSize() {
        return Integer.parseInt(properties.getProperty("global.font.size", "12"));
    }

    public void setGlobalFontSize(int size) {
        properties.setProperty("global.font.size", String.valueOf(size));
    }

    public Font getGlobalFont() {
        return new Font(getGlobalFontName(), getGlobalFontStyle(), getGlobalFontSize());
    }

    public void setGlobalFont(Font font) {
        setGlobalFontName(font.getName());
        setGlobalFontSize(font.getSize());
        setGlobalFontStyle(font.getStyle());
    }

    public int getGlobalFontStyle() {
        return Integer.parseInt(properties.getProperty("global.font.style", String.valueOf(Font.PLAIN)));
    }

    public void setGlobalFontStyle(int style) {
        properties.setProperty("global.font.style", String.valueOf(style));
    }

    // Colors stored as hex strings (e.g. #RRGGBB)
    public Color getBackgroundColor() {
        String v = properties.getProperty("appearance.bg", null);
        if (v == null) return null;
        try { return Color.decode(v); } catch (Exception ex) { return null; }
    }

    public void setBackgroundColor(Color c) {
        if (c == null) {
            properties.remove("appearance.bg");
        } else {
            properties.setProperty("appearance.bg", String.format("#%02x%02x%02x", c.getRed(), c.getGreen(), c.getBlue()));
        }
    }

    public Color getSelectionColor() {
        String v = properties.getProperty("appearance.selection", null);
        if (v == null) return null;
        try { return Color.decode(v); } catch (Exception ex) { return null; }
    }

    public void setSelectionColor(Color c) {
        if (c == null) {
            properties.remove("appearance.selection");
        } else {
            properties.setProperty("appearance.selection", String.format("#%02x%02x%02x", c.getRed(), c.getGreen(), c.getBlue()));
        }
    }

    public Color getMarkedColor() {
        String v = properties.getProperty("appearance.marked", null);
        if (v == null) return null;
        try { return Color.decode(v); } catch (Exception ex) { return null; }
    }

    public void setMarkedColor(Color c) {
        if (c == null) {
            properties.remove("appearance.marked");
        } else {
            properties.setProperty("appearance.marked", String.format("#%02x%02x%02x", c.getRed(), c.getGreen(), c.getBlue()));
        }
    }

    public Color getFolderColor() {
        String v = properties.getProperty("appearance.folder", null);
        if (v == null) return new Color(255, 200, 0); // Default yellow/gold
        try { return Color.decode(v); } catch (Exception ex) { return new Color(255, 200, 0); }
    }

    public void setFolderColor(Color c) {
        if (c == null) {
            properties.remove("appearance.folder");
        } else {
            properties.setProperty("appearance.folder", String.format("#%02x%02x%02x", c.getRed(), c.getGreen(), c.getBlue()));
        }
    }

    // -- Sorting persistence (global default)
    public int getDefaultSortColumn() {
        return Integer.parseInt(properties.getProperty("global.sort.column", "-1"));
    }

    public void setDefaultSortColumn(int col) {
        properties.setProperty("global.sort.column", String.valueOf(col));
    }

    public boolean getDefaultSortAscending() {
        return Boolean.parseBoolean(properties.getProperty("global.sort.ascending", "true"));
    }

    public void setDefaultSortAscending(boolean asc) {
        properties.setProperty("global.sort.ascending", String.valueOf(asc));
    }

    // Hidden files ordering: true = hidden after visible (default true)
    public boolean getHiddenFilesLast() {
        return Boolean.parseBoolean(properties.getProperty("global.sort.hidden.last", "true"));
    }

    public void setHiddenFilesLast(boolean last) {
        properties.setProperty("global.sort.hidden.last", String.valueOf(last));
    }

    // Uppercase preference: when names equal ignoring case, prefer uppercase first
    public boolean getUppercasePriority() {
        return Boolean.parseBoolean(properties.getProperty("global.sort.uppercase.priority", "true"));
    }

    public void setUppercasePriority(boolean priority) {
        properties.setProperty("global.sort.uppercase.priority", String.valueOf(priority));
    }

    // Numeric-aware name sorting (natural sort): default true
    public boolean getNumericSortEnabled() {
        return Boolean.parseBoolean(properties.getProperty("global.sort.numeric.enabled", "true"));
    }

    public void setNumericSortEnabled(boolean enabled) {
        properties.setProperty("global.sort.numeric.enabled", String.valueOf(enabled));
    }

    // Ignore leading dot in names when sorting (treat ".name" as "name")
    public boolean getIgnoreLeadingDot() {
        return Boolean.parseBoolean(properties.getProperty("global.sort.ignore.leadingdot", "false"));
    }

    public void setIgnoreLeadingDot(boolean enabled) {
        properties.setProperty("global.sort.ignore.leadingdot", String.valueOf(enabled));
    }
    
    // -- Multiple sort criteria persistence
    public java.util.List<String> getMultipleSortCriteria() {
        java.util.List<String> list = new java.util.ArrayList<>();
        int count = Integer.parseInt(properties.getProperty("global.sort.criteria.count", "0"));
        for (int i = 0; i < count; i++) {
            String v = properties.getProperty("global.sort.criteria." + i, null);
            if (v != null && !v.isEmpty()) list.add(v);
        }
        return list;
    }

    public void setMultipleSortCriteria(java.util.List<String> criteria) {
        if (criteria == null || criteria.isEmpty()) {
            properties.setProperty("global.sort.criteria.count", "0");
            return;
        }
        
        int limit = Math.min(criteria.size(), 5); // cap stored entries
        properties.setProperty("global.sort.criteria.count", String.valueOf(limit));
        for (int i = 0; i < limit; i++) {
            properties.setProperty("global.sort.criteria." + i, criteria.get(i));
        }
        
        // remove any old entries beyond limit
        int old = Integer.parseInt(properties.getProperty("global.sort.criteria.count", "0"));
        for (int i = limit; i < old; i++) {
            properties.remove("global.sort.criteria." + i);
        }
    }
    
    /**
     * Save window state
     */
    public void saveWindowState(Frame frame) {
        if (frame.getExtendedState() == Frame.MAXIMIZED_BOTH) {
            setWindowMaximized(true);
        } else {
            setWindowMaximized(false);
            setWindowX(frame.getX());
            setWindowY(frame.getY());
            setWindowWidth(frame.getWidth());
            setWindowHeight(frame.getHeight());
        }
    }
    
    /**
     * Restore window state
     */
    public void restoreWindowState(Frame frame) {
        frame.setLocation(getWindowX(), getWindowY());
        frame.setSize(getWindowWidth(), getWindowHeight());
        
        if (isWindowMaximized()) {
            frame.setExtendedState(Frame.MAXIMIZED_BOTH);
        }
    }

    // --- Search dialog persistence ---
    public int getSearchDialogX() {
        return Integer.parseInt(properties.getProperty("searchDialog.x", "100"));
    }

    public void setSearchDialogX(int x) {
        properties.setProperty("searchDialog.x", String.valueOf(x));
    }

    public int getSearchDialogY() {
        return Integer.parseInt(properties.getProperty("searchDialog.y", "100"));
    }

    public void setSearchDialogY(int y) {
        properties.setProperty("searchDialog.y", String.valueOf(y));
    }

    public int getSearchDialogWidth() {
        return Integer.parseInt(properties.getProperty("searchDialog.width", "700"));
    }

    public void setSearchDialogWidth(int w) {
        properties.setProperty("searchDialog.width", String.valueOf(w));
    }

    public int getSearchDialogHeight() {
        return Integer.parseInt(properties.getProperty("searchDialog.height", "500"));
    }

    public void setSearchDialogHeight(int h) {
        properties.setProperty("searchDialog.height", String.valueOf(h));
    }

    /** Save search dialog bounds */
    public void saveSearchDialogState(Window win) {
        if (win == null) return;
        setSearchDialogX(win.getX());
        setSearchDialogY(win.getY());
        setSearchDialogWidth(win.getWidth());
        setSearchDialogHeight(win.getHeight());
    }

    /** Restore search dialog bounds */
    public void restoreSearchDialogState(Window win) {
        if (win == null) return;
        win.setLocation(getSearchDialogX(), getSearchDialogY());
        win.setSize(getSearchDialogWidth(), getSearchDialogHeight());
    }

    // --- Search history persistence ---
    public java.util.List<String> getSearchHistory() {
        java.util.List<String> list = new java.util.ArrayList<>();
        int count = Integer.parseInt(properties.getProperty("search.history.count", "0"));
        for (int i = 0; i < count; i++) {
            String v = properties.getProperty("search.history." + i, null);
            if (v != null && !v.isEmpty()) list.add(v);
        }
        return list;
    }

    public void saveSearchHistory(java.util.List<String> history) {
        if (history == null) {
            properties.setProperty("search.history.count", "0");
            return;
        }
        int limit = Math.min(history.size(), 50); // cap stored entries
        properties.setProperty("search.history.count", String.valueOf(limit));
        for (int i = 0; i < limit; i++) {
            properties.setProperty("search.history." + i, history.get(i));
        }
        // remove any old entries beyond limit
        int old = Integer.parseInt(properties.getProperty("search.history.count", "0"));
        for (int i = limit; i < old; i++) {
            properties.remove("search.history." + i);
        }
    }

    // --- Content search history persistence ---
    public java.util.List<String> getContentSearchHistory() {
        java.util.List<String> list = new java.util.ArrayList<>();
        int count = Integer.parseInt(properties.getProperty("search.content.history.count", "0"));
        for (int i = 0; i < count; i++) {
            String v = properties.getProperty("search.content.history." + i, null);
            if (v != null && !v.isEmpty()) list.add(v);
        }
        return list;
    }

    public void saveContentSearchHistory(java.util.List<String> history) {
        if (history == null) {
            properties.setProperty("search.content.history.count", "0");
            return;
        }
        int limit = Math.min(history.size(), 50);
        properties.setProperty("search.content.history.count", String.valueOf(limit));
        for (int i = 0; i < limit; i++) {
            properties.setProperty("search.content.history." + i, history.get(i));
        }
        // remove old entries beyond limit
        int old = Integer.parseInt(properties.getProperty("search.content.history.count", "0"));
        for (int i = limit; i < old; i++) {
            properties.remove("search.content.history." + i);
        }
    }

    // --- Command line history persistence ---
    public java.util.List<String> getCommandLineHistory() {
        java.util.List<String> list = new java.util.ArrayList<>();
        int count = Integer.parseInt(properties.getProperty("cmd.history.count", "0"));
        for (int i = 0; i < count; i++) {
            String v = properties.getProperty("cmd.history." + i, null);
            if (v != null && !v.isEmpty()) list.add(v);
        }
        return list;
    }

    public void saveCommandLineHistory(java.util.List<String> history) {
        if (history == null) {
            properties.setProperty("cmd.history.count", "0");
            return;
        }
        int limit = Math.min(history.size(), 50);
        properties.setProperty("cmd.history.count", String.valueOf(limit));
        for (int i = 0; i < limit; i++) {
            properties.setProperty("cmd.history." + i, history.get(i));
        }
        // remove old entries beyond limit
        int old = Integer.parseInt(properties.getProperty("cmd.history.count", "0"));
        for (int i = limit; i < old; i++) {
            properties.remove("cmd.history." + i);
        }
    }

    // --- Toolbar shortcuts persistence ---
    public static class ToolbarShortcut implements Serializable {
        public String command;
        public String label;
        public String iconPath;
        public String workingDir;

        public ToolbarShortcut(String command, String label, String iconPath, String workingDir) {
            this.command = command;
            this.label = label;
            this.iconPath = iconPath;
            this.workingDir = workingDir;
        }
    }

    public java.util.List<ToolbarShortcut> getToolbarShortcuts() {
        java.util.List<ToolbarShortcut> list = new java.util.ArrayList<>();
        int count = Integer.parseInt(properties.getProperty("toolbar.shortcuts.count", "0"));
        for (int i = 0; i < count; i++) {
            String cmd = properties.getProperty("toolbar.shortcut." + i + ".command");
            String label = properties.getProperty("toolbar.shortcut." + i + ".label");
            String icon = properties.getProperty("toolbar.shortcut." + i + ".iconPath");
            String workDir = properties.getProperty("toolbar.shortcut." + i + ".workingDir");
            if (cmd != null) {
                list.add(new ToolbarShortcut(cmd, label, icon, workDir));
            }
        }
        return list;
    }

    public void saveToolbarShortcuts(java.util.List<ToolbarShortcut> shortcuts) {
        // remove old entries first
        int old = Integer.parseInt(properties.getProperty("toolbar.shortcuts.count", "0"));
        for (int i = 0; i < old; i++) {
            properties.remove("toolbar.shortcut." + i + ".command");
            properties.remove("toolbar.shortcut." + i + ".label");
            properties.remove("toolbar.shortcut." + i + ".iconPath");
            properties.remove("toolbar.shortcut." + i + ".workingDir");
        }

        properties.setProperty("toolbar.shortcuts.count", String.valueOf(shortcuts.size()));
        for (int i = 0; i < shortcuts.size(); i++) {
            ToolbarShortcut s = shortcuts.get(i);
            properties.setProperty("toolbar.shortcut." + i + ".command", s.command != null ? s.command : "");
            properties.setProperty("toolbar.shortcut." + i + ".label", s.label != null ? s.label : "");
            properties.setProperty("toolbar.shortcut." + i + ".iconPath", s.iconPath != null ? s.iconPath : "");
            properties.setProperty("toolbar.shortcut." + i + ".workingDir", s.workingDir != null ? s.workingDir : "");
        }
    }
}
