package com.huangzj.protoplugin.memo;

import com.intellij.openapi.project.Project;
import com.intellij.ui.JBColor;
import com.intellij.ui.components.JBList;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.components.JBTextArea;
import com.intellij.ui.components.JBTextField;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UIUtil;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.jetbrains.annotations.NotNull;

public final class MemoPanel extends JPanel {

    private final Project project;
    private final DefaultListModel<MemoItem> listModel = new DefaultListModel<>();
    private final JBList<MemoItem> list = new JBList<>(listModel);
    private final JBTextField titleField = new JBTextField();
    private final JBTextArea contentArea = new JBTextArea();
    private final JButton saveBtn = new JButton("保存");
    private final JButton newBtn = new JButton("新建");
    private final JButton deleteBtn = new JButton("删除");
    private final JLabel themeChooserLabel = new JLabel("界面风格");
    private final JComboBox<MemoUiTheme> themeCombo = new JComboBox<>(MemoUiTheme.values());
    private final JLabel titleLabel = new JLabel("标题");
    private final JLabel contentLabel = new JLabel("内容");
    private final JLabel flairLabel = new JLabel(" ", SwingConstants.CENTER);
    private final JPanel toolbar = new JPanel(new BorderLayout(8, 0));
    private final JPanel leftButtonBar = new JPanel(new FlowLayout(FlowLayout.LEFT, 8, 0));
    private final JPanel themeChooserBar = new JPanel(new FlowLayout(FlowLayout.RIGHT, 8, 0));
    private final JPanel topStack = new JPanel(new BorderLayout());
    private JSplitPane split;
    private JBScrollPane listScroll;
    private JBScrollPane contentScroll;
    private final JPanel titleBlock = new JPanel(new BorderLayout(4, 4));
    private final JPanel contentBlock = new JPanel(new BorderLayout(4, 4));
    private final JPanel right = new JPanel(new BorderLayout(8, 8));
    private final JBTextField searchField = new JBTextField();
    private final JLabel countLabel = new JLabel(" ");
    private final JLabel modifiedLabel = new JLabel(" ");
    private final JPanel leftPanel = new JPanel(new BorderLayout(0, 4));
    private final JPanel searchPanel = new JPanel(new BorderLayout(4, 0));
    private final JLabel searchIcon = new JLabel("\uD83D\uDD0D");
    private final JPanel editorStatusBar = new JPanel(new BorderLayout());

    private boolean loadingSelection;
    private boolean themeComboSuppress;
    private MemoUiTheme currentTheme = MemoUiTheme.IDE_DEFAULT;
    private final Font defaultLabelFont;
    private List<MemoItem> allItems = new ArrayList<>();

    public MemoPanel(@NotNull Project project) {
        super(new BorderLayout(8, 8));
        this.project = project;
        defaultLabelFont = titleLabel.getFont();
        setBorder(JBUI.Borders.empty(8));

        initToolbar();
        initFlair();
        initTopStack();
        initSearchPanel();
        initList();
        initLeftPanel();
        initEditor();
        initSplit();
        initTheme();
        initListeners();

        reloadListModel();
    }

    private void initToolbar() {
        leftButtonBar.setOpaque(false);
        newBtn.setToolTipText("新建一条备忘录");
        saveBtn.setToolTipText("保存当前备忘录");
        deleteBtn.setToolTipText("删除选中的备忘录");
        leftButtonBar.add(newBtn);
        leftButtonBar.add(saveBtn);
        leftButtonBar.add(deleteBtn);

        themeChooserBar.setOpaque(false);
        themeChooserBar.add(themeChooserLabel);
        themeChooserBar.add(themeCombo);

        toolbar.setOpaque(false);
        toolbar.add(leftButtonBar, BorderLayout.WEST);
        toolbar.add(themeChooserBar, BorderLayout.EAST);
    }

    private void initFlair() {
        flairLabel.setOpaque(true);
        flairLabel.setFont(flairLabel.getFont().deriveFont(Font.PLAIN, 12f));
    }

    private void initTopStack() {
        topStack.setOpaque(false);
        topStack.add(flairLabel, BorderLayout.NORTH);
        topStack.add(toolbar, BorderLayout.CENTER);
        add(topStack, BorderLayout.NORTH);
    }

    private void initSearchPanel() {
        searchField.getEmptyText().setText("搜索备忘录...");
        searchField.setToolTipText("输入关键字过滤备忘录标题和内容");
        searchPanel.setOpaque(false);
        searchPanel.add(searchIcon, BorderLayout.WEST);
        searchPanel.add(searchField, BorderLayout.CENTER);
        searchPanel.setBorder(JBUI.Borders.empty(0, 0, 4, 0));
    }

    private void initList() {
        list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        installListRenderer();
        listScroll = new JBScrollPane(list);
        listScroll.setPreferredSize(new Dimension(200, 300));

        countLabel.setFont(countLabel.getFont().deriveFont(Font.PLAIN, 11f));
        countLabel.setHorizontalAlignment(SwingConstants.RIGHT);
        countLabel.setBorder(JBUI.Borders.empty(2, 4, 0, 4));
    }

    private void initLeftPanel() {
        leftPanel.setOpaque(false);
        leftPanel.add(searchPanel, BorderLayout.NORTH);
        leftPanel.add(listScroll, BorderLayout.CENTER);
        leftPanel.add(countLabel, BorderLayout.SOUTH);
    }

    private void initEditor() {
        contentArea.setLineWrap(true);
        contentArea.setWrapStyleWord(true);
        contentScroll = new JBScrollPane(contentArea);

        titleBlock.setOpaque(false);
        titleBlock.add(titleLabel, BorderLayout.NORTH);
        titleBlock.add(titleField, BorderLayout.CENTER);

        contentBlock.setOpaque(false);
        contentBlock.add(contentLabel, BorderLayout.NORTH);
        contentBlock.add(contentScroll, BorderLayout.CENTER);

        modifiedLabel.setFont(modifiedLabel.getFont().deriveFont(Font.PLAIN, 11f));
        modifiedLabel.setBorder(JBUI.Borders.empty(2, 0, 0, 0));
        editorStatusBar.setOpaque(false);
        editorStatusBar.add(modifiedLabel, BorderLayout.EAST);

        right.setOpaque(false);
        right.add(titleBlock, BorderLayout.NORTH);
        right.add(contentBlock, BorderLayout.CENTER);
        right.add(editorStatusBar, BorderLayout.SOUTH);
        titleField.setPreferredSize(new Dimension(200, 28));
    }

    private void initSplit() {
        split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel, right);
        split.setResizeWeight(0.28);
        split.setOpaque(false);
        add(split, BorderLayout.CENTER);
    }

    private void initTheme() {
        MemoUiTheme initial = MemoProjectService.getInstance(project).getMemoTheme();
        themeComboSuppress = true;
        themeCombo.setSelectedItem(initial);
        themeComboSuppress = false;
        applyTheme(initial);
    }

    private void initListeners() {
        themeCombo.addActionListener(
                e -> {
                    if (themeComboSuppress) {
                        return;
                    }
                    MemoUiTheme t = (MemoUiTheme) themeCombo.getSelectedItem();
                    if (t != null) {
                        MemoProjectService.getInstance(project).setMemoTheme(t);
                        applyTheme(t);
                    }
                });

        list.addListSelectionListener(
                new ListSelectionListener() {
                    @Override
                    public void valueChanged(ListSelectionEvent e) {
                        if (e.getValueIsAdjusting()) {
                            return;
                        }
                        loadSelectedIntoEditor();
                    }
                });

        newBtn.addActionListener(e -> createMemo());
        saveBtn.addActionListener(e -> saveCurrent());
        deleteBtn.addActionListener(e -> deleteCurrent());

        titleField
                .getDocument()
                .addDocumentListener(
                        new javax.swing.event.DocumentListener() {
                            @Override
                            public void insertUpdate(javax.swing.event.DocumentEvent e) {
                                refreshSelectedTitleInList();
                            }

                            @Override
                            public void removeUpdate(javax.swing.event.DocumentEvent e) {
                                refreshSelectedTitleInList();
                            }

                            @Override
                            public void changedUpdate(javax.swing.event.DocumentEvent e) {
                                refreshSelectedTitleInList();
                            }
                        });

        searchField
                .getDocument()
                .addDocumentListener(
                        new javax.swing.event.DocumentListener() {
                            @Override
                            public void insertUpdate(javax.swing.event.DocumentEvent e) {
                                filterList();
                            }

                            @Override
                            public void removeUpdate(javax.swing.event.DocumentEvent e) {
                                filterList();
                            }

                            @Override
                            public void changedUpdate(javax.swing.event.DocumentEvent e) {
                                filterList();
                            }
                        });
    }

    private void installListRenderer() {
        list.setCellRenderer(
                new DefaultListCellRenderer() {
                    @Override
                    public Component getListCellRendererComponent(
                            JList<?> jList,
                            Object value,
                            int index,
                            boolean isSelected,
                            boolean cellHasFocus) {
                        JLabel label = (JLabel) super.getListCellRendererComponent(
                                jList, value, index, isSelected, cellHasFocus);
                        if (value instanceof MemoItem) {
                            MemoItem item = (MemoItem) value;
                            String title = escapeHtml(item.displayTitle());
                            String date = item.displayDate();
                            String preview = item.contentPreview();

                            StringBuilder html = new StringBuilder(128);
                            html.append("<html><body style='width:160px'>");
                            html.append("<b>").append(title).append("</b>");
                            if (!date.isEmpty()) {
                                html.append("<br><span style='font-size:10px;color:")
                                        .append(isSelected ? "#inherit" : "#888888")
                                        .append("'>").append(date).append("</span>");
                            }
                            if (!preview.isEmpty()) {
                                html.append("<br><span style='font-size:10px;color:")
                                        .append(isSelected ? "#inherit" : "#AAAAAA")
                                        .append("'>").append(escapeHtml(preview)).append("</span>");
                            }
                            html.append("</body></html>");
                            label.setText(html.toString());
                        }
                        if (currentTheme != MemoUiTheme.IDE_DEFAULT) {
                            MemoThemeSpec spec = MemoThemeSpec.forTheme(currentTheme);
                            label.setOpaque(true);
                            if (isSelected) {
                                label.setBackground(spec.listSelectedBg);
                                label.setForeground(spec.listSelectedFg);
                            } else {
                                label.setBackground(spec.listBg);
                                label.setForeground(spec.text);
                            }
                        }
                        label.setBorder(JBUI.Borders.empty(4, 8, 4, 8));
                        return label;
                    }
                });
    }

    private static String escapeHtml(String text) {
        if (text == null) {
            return "";
        }
        return text.replace("&", "&amp;")
                .replace("<", "&lt;")
                .replace(">", "&gt;")
                .replace("\"", "&quot;");
    }

    private void applyTheme(@NotNull MemoUiTheme theme) {
        currentTheme = theme;
        installListRenderer();
        list.repaint();

        if (theme == MemoUiTheme.IDE_DEFAULT) {
            applyIdeTheme();
            return;
        }

        MemoThemeSpec spec = MemoThemeSpec.forTheme(theme);
        Border softField =
                JBUI.Borders.compound(
                        new LineBorder(spec.fieldBorder, 1, true),
                        JBUI.Borders.empty(4, 6));

        Color panelBg = spec.panelBg;
        setBackground(panelBg);
        topStack.setOpaque(true);
        topStack.setBackground(panelBg);
        toolbar.setBackground(panelBg);
        toolbar.setOpaque(true);
        leftButtonBar.setOpaque(true);
        leftButtonBar.setBackground(panelBg);
        themeChooserBar.setOpaque(true);
        themeChooserBar.setBackground(panelBg);
        themeChooserLabel.setForeground(spec.text);
        flairLabel.setBackground(panelBg);
        flairLabel.setForeground(spec.text);
        split.setBackground(panelBg);
        leftPanel.setBackground(panelBg);
        searchPanel.setBackground(panelBg);
        searchIcon.setForeground(spec.text);
        listScroll.setBackground(panelBg);
        listScroll.getViewport().setBackground(spec.listBg);
        list.setBackground(spec.listBg);
        list.setForeground(spec.text);
        right.setBackground(panelBg);
        titleBlock.setBackground(panelBg);
        contentBlock.setBackground(panelBg);
        titleLabel.setForeground(spec.text);
        contentLabel.setForeground(spec.text);
        countLabel.setForeground(spec.text);
        modifiedLabel.setForeground(spec.text);
        editorStatusBar.setBackground(panelBg);

        if (theme == MemoUiTheme.CUTE_CANDY) {
            flairLabel.setVisible(true);
            flairLabel.setText("\u2728 今天也要甜甜哒\uFF5E 选一条备忘，把想法留下来吧 \uD83D\uDC95");
            titleLabel.setText("\uD83D\uDCDD 标题");
            contentLabel.setText("\uD83D\uDC97 正文");
            titleLabel.setFont(defaultLabelFont.deriveFont(Font.BOLD, defaultLabelFont.getSize() + 1f));
            contentLabel.setFont(
                    defaultLabelFont.deriveFont(Font.BOLD, defaultLabelFont.getSize() + 1f));
        } else {
            flairLabel.setVisible(false);
            flairLabel.setText(" ");
            titleLabel.setText("标题");
            contentLabel.setText("内容");
            titleLabel.setFont(defaultLabelFont);
            contentLabel.setFont(defaultLabelFont);
        }

        styleTextField(titleField, spec, softField);
        styleTextField(searchField, spec, softField);
        styleTextArea(contentArea, contentScroll, spec, softField);

        styleAccentButton(newBtn, spec);
        styleAccentButton(saveBtn, spec);
        styleAccentButton(deleteBtn, spec);

        themeCombo.setBackground(spec.editorBg);
        themeCombo.setForeground(spec.text);

        revalidate();
        repaint();
    }

    private void applyIdeTheme() {
        Color panelBg = UIUtil.getPanelBackground();
        Color editorBg = UIUtil.getTextFieldBackground();
        Color fg = UIUtil.getTextFieldForeground();
        Color listBg = UIUtil.getListBackground();
        Color labelFg = UIUtil.getLabelForeground();

        setBackground(panelBg);
        topStack.setOpaque(false);
        topStack.setBackground(panelBg);
        toolbar.setBackground(panelBg);
        toolbar.setOpaque(false);
        leftButtonBar.setOpaque(false);
        themeChooserBar.setOpaque(false);
        themeChooserLabel.setForeground(labelFg);
        flairLabel.setVisible(false);
        flairLabel.setText(" ");
        flairLabel.setBackground(panelBg);
        flairLabel.setForeground(labelFg);
        split.setBackground(panelBg);
        leftPanel.setBackground(panelBg);
        searchPanel.setBackground(panelBg);
        searchIcon.setForeground(labelFg);
        listScroll.setBackground(panelBg);
        listScroll.getViewport().setBackground(listBg);
        list.setBackground(listBg);
        list.setForeground(UIUtil.getTreeForeground());
        right.setBackground(panelBg);
        titleBlock.setBackground(panelBg);
        contentBlock.setBackground(panelBg);
        titleLabel.setText("标题");
        contentLabel.setText("内容");
        titleLabel.setFont(defaultLabelFont);
        contentLabel.setFont(defaultLabelFont);
        titleLabel.setForeground(labelFg);
        contentLabel.setForeground(labelFg);
        countLabel.setForeground(JBColor.GRAY);
        modifiedLabel.setForeground(JBColor.GRAY);
        editorStatusBar.setBackground(panelBg);

        resetFieldLook(titleField, editorBg, fg);
        resetFieldLook(searchField, editorBg, fg);
        resetFieldLook(contentArea, editorBg, fg);
        contentScroll.getViewport().setBackground(editorBg);
        contentArea.setCaretColor(fg);
        titleField.setCaretColor(fg);
        searchField.setCaretColor(fg);

        resetButton(newBtn);
        resetButton(saveBtn);
        resetButton(deleteBtn);

        resetCombo(themeCombo);

        revalidate();
        repaint();
    }

    private static void resetFieldLook(javax.swing.text.JTextComponent c, Color bg, Color fg) {
        c.setOpaque(true);
        c.setBackground(bg);
        c.setForeground(fg);
        c.setBorder(
                JBUI.Borders.compound(
                        JBUI.Borders.customLine(UIUtil.getBoundsColor(), 1),
                        JBUI.Borders.empty(4, 6)));
        Color selBg = UIManager.getColor("TextArea.selectionBackground");
        if (selBg == null) {
            selBg = UIUtil.getListSelectionBackground();
        }
        Color selFg = UIManager.getColor("TextArea.selectionForeground");
        if (selFg == null) {
            selFg = UIUtil.getListSelectionForeground();
        }
        c.setSelectionColor(selBg);
        c.setSelectedTextColor(selFg);
    }

    private static void resetButton(JButton b) {
        b.setOpaque(false);
        b.setBackground(null);
        b.setForeground(null);
        b.setBorder(JBUI.Borders.empty(4, 12));
    }

    private static void resetCombo(JComboBox<?> combo) {
        combo.setOpaque(true);
        combo.setBackground(null);
        combo.setForeground(null);
    }

    private static void styleTextField(JBTextField field, MemoThemeSpec spec, Border border) {
        field.setOpaque(true);
        field.setBackground(spec.editorBg);
        field.setForeground(spec.text);
        field.setBorder(border);
        field.setCaretColor(spec.text);
        field.setSelectedTextColor(spec.listSelectedFg);
        field.setSelectionColor(spec.listSelectedBg);
    }

    private static void styleTextArea(
            JBTextArea area, JScrollPane scroll, MemoThemeSpec spec, Border border) {
        area.setOpaque(true);
        area.setBackground(spec.editorBg);
        area.setForeground(spec.text);
        area.setBorder(JBUI.Borders.empty());
        area.setCaretColor(spec.text);
        area.setSelectedTextColor(spec.listSelectedFg);
        area.setSelectionColor(spec.listSelectedBg);
        scroll.setBorder(border);
        scroll.getViewport().setBackground(spec.editorBg);
    }

    private static void styleAccentButton(JButton b, MemoThemeSpec spec) {
        b.setOpaque(true);
        b.setBackground(spec.buttonBg);
        b.setForeground(spec.buttonFg);
        b.setBorder(
                JBUI.Borders.compound(
                        new LineBorder(spec.accent, 1, true), JBUI.Borders.empty(5, 14)));
        b.setFocusPainted(false);
    }

    private void reloadListModel() {
        allItems = MemoProjectService.getInstance(project).getItems();
        filterList();
    }

    private void filterList() {
        String query = searchField.getText().trim().toLowerCase();
        listModel.clear();

        List<MemoItem> filtered;
        if (query.isEmpty()) {
            filtered = allItems;
        } else {
            filtered = allItems.stream()
                    .filter(m -> matchesQuery(m, query))
                    .collect(Collectors.toList());
        }

        for (MemoItem m : filtered) {
            listModel.addElement(m);
        }

        updateCountLabel(filtered.size());

        if (!filtered.isEmpty() && list.getSelectedIndex() < 0) {
            list.setSelectedIndex(0);
        }

        if (filtered.isEmpty() && !allItems.isEmpty() && !query.isEmpty()) {
            clearEditor();
            modifiedLabel.setText("无匹配结果");
        } else if (filtered.isEmpty() && allItems.isEmpty()) {
            clearEditor();
            modifiedLabel.setText(" ");
        }
    }

    private static boolean matchesQuery(MemoItem m, String query) {
        if (m.title != null && m.title.toLowerCase().contains(query)) {
            return true;
        }
        if (m.content != null && m.content.toLowerCase().contains(query)) {
            return true;
        }
        return false;
    }

    private void updateCountLabel(int visibleCount) {
        int total = allItems.size();
        if (total == 0) {
            countLabel.setText(" ");
        } else if (visibleCount == total) {
            countLabel.setText("共 " + total + " 条");
        } else {
            countLabel.setText("显示 " + visibleCount + " / " + total + " 条");
        }
    }

    private void createMemo() {
        MemoItem m = MemoProjectService.getInstance(project).createMemo();
        allItems = MemoProjectService.getInstance(project).getItems();
        searchField.setText("");
        filterList();
        list.setSelectedValue(m, true);
        titleField.requestFocusInWindow();
    }

    private void saveCurrent() {
        MemoItem m = list.getSelectedValue();
        if (m == null) {
            return;
        }
        m.title = titleField.getText();
        m.content = contentArea.getText();
        m.updated = System.currentTimeMillis();
        allItems = MemoProjectService.getInstance(project).getItems();
        list.repaint();
        updateModifiedLabel(m);
    }

    private void deleteCurrent() {
        MemoItem m = list.getSelectedValue();
        if (m == null) {
            return;
        }
        String itemTitle = m.displayTitle();
        int result = JOptionPane.showConfirmDialog(
                this,
                "确定要删除「" + itemTitle + "」吗？\n此操作不可撤销。",
                "确认删除",
                JOptionPane.YES_NO_OPTION,
                JOptionPane.WARNING_MESSAGE);
        if (result != JOptionPane.YES_OPTION) {
            return;
        }
        int idx = list.getSelectedIndex();
        MemoProjectService.getInstance(project).removeById(m.id);
        allItems = MemoProjectService.getInstance(project).getItems();
        listModel.removeElement(m);
        updateCountLabel(listModel.getSize());
        if (!listModel.isEmpty()) {
            int next = Math.min(idx, listModel.getSize() - 1);
            list.setSelectedIndex(Math.max(0, next));
        } else {
            clearEditor();
        }
    }

    private void loadSelectedIntoEditor() {
        MemoItem m = list.getSelectedValue();
        loadingSelection = true;
        try {
            if (m == null) {
                clearEditor();
            } else {
                titleField.setText(m.title != null ? m.title : "");
                contentArea.setText(m.content != null ? m.content : "");
                updateModifiedLabel(m);
            }
        } finally {
            loadingSelection = false;
        }
    }

    private void updateModifiedLabel(MemoItem m) {
        String date = m.displayDate();
        if (!date.isEmpty()) {
            modifiedLabel.setText("最后修改: " + date);
        } else {
            modifiedLabel.setText(" ");
        }
    }

    private void clearEditor() {
        titleField.setText("");
        contentArea.setText("");
        modifiedLabel.setText(" ");
    }

    private void refreshSelectedTitleInList() {
        if (loadingSelection) {
            return;
        }
        javax.swing.SwingUtilities.invokeLater(() -> list.repaint());
    }
}