package com.fr.startup.ui;

import com.fr.base.svg.IconUtils;
import com.fr.concurrent.NamedThreadFactory;
import com.fr.design.DesignerEnvManager;
import com.fr.design.dialog.UIExpandDialog;
import com.fr.design.gui.icontainer.UIScrollPane;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.layout.VerticalFlowLayout;
import com.fr.design.mainframe.messagecollect.StartErrorMessageCollector;
import com.fr.design.mainframe.messagecollect.entity.DesignerErrorMessage;
import com.fr.design.ui.util.UIUtil;
import com.fr.design.utils.ColorUtils;
import com.fr.design.utils.ThemeUtils;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.exit.DesignerExiter;
import com.fr.general.GeneralUtils;
import com.fr.general.IOUtils;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.ProductConstants;
import com.fr.stable.collections.CollectionUtils;
import com.fr.stable.os.OperatingSystem;
import com.fr.start.common.DesignerStartupContext;
import com.fr.startup.metric.DesignerMetrics;
import org.jetbrains.annotations.NotNull;

import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.SwingWorker;
import javax.swing.border.EmptyBorder;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.LayoutManager;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 启动页
 * 见<a href="https://kms.fineres.com/pages/viewpage.action?pageId=416850313">设计文档</a>
 * <p>
 * created by Harrison on 2022/07/06
 **/
public class StartupPageWindow extends JFrame {
    
    private static final Color HOVER_COLOR = new Color(65, 155, 249);
    private static final Color SEP_COLOR = new Color(224, 224, 225);
    
    private static final int GROUP_WIDTH = 600;
    private static final int RECENT_FILE_LIMIT = 6;
    private static final int RECENT_FILE_SCROLL = RECENT_FILE_LIMIT + 1;
    private static final int WORKSPACE_PANEL_WIDTH = 180;
    private static final int TITLE_FONT_SIZE = 24;
    private static final int ITEM_VERTICAL_GAP = 5;
    
    private static final Dimension SCREEN_SIZE = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
    
    private static final BufferedImage BACKGROUND_IMAGE = IOUtils.readImage("com/fr/design/startup/startup_page_background.jpg");
    
    private StartupPageWorkspacePanel workspacePanel;
    
    private JPanel recentOpenPanel;
    
    private JPanel contentPane;
    
    private JPanel body;
    
    public StartupPageWindow(StartupPageModel pageModel) {
    
        patchUIAction(pageModel);
    
        setLayout(new BorderLayout());
    
        initCenter(pageModel);
    
        // Workspace-detail
        setSize(SCREEN_SIZE);
        setDefaultTitle();
        addDefaultListeners();
        
        repaint();
        validate();
        revalidate();
        
        setFullScreen();
    
    }
    
    private void initCenter(StartupPageModel pageModel) {
    
        initHeaderPanel();
    
        initWorkspacePanel(pageModel);
    
        initRecentOpenPanel(pageModel);
        initContentPanel();
    }
    
    private void initHeaderPanel() {
        this.body = FRGUIPaneFactory.createBorderLayout_S_Pane();
        this.body.setBackground(new Color(0, 0, 0, 0));
        JPanel headerPanel = createHeader();
        this.body.add(headerPanel, BorderLayout.NORTH);
    }
    
    private void initRecentOpenPanel(StartupPageModel pageModel) {
        
        this.recentOpenPanel = generateRecentOpenPanel(pageModel);
        this.body.add(recentOpenPanel, BorderLayout.SOUTH);
    }
    
    private void initContentPanel() {
        this.contentPane = new JPanel() {
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                g.drawImage(BACKGROUND_IMAGE, 0, 0, SCREEN_SIZE.width, SCREEN_SIZE.height, this);
            }
        };
        this.contentPane.setLayout(getCenterLayout(body));
        this.contentPane.add(this.body, BorderLayout.CENTER);
        this.contentPane.setPreferredSize(this.body.getPreferredSize());
        
        add(this.contentPane, BorderLayout.CENTER);
    }
    
    private void initWorkspacePanel(StartupPageModel pageModel) {
        
        // Workspace-description
        this.workspacePanel = generateWorkspacePanel(pageModel);
        this.body.add(workspacePanel, BorderLayout.CENTER);
        
        workspacePanel.setSelectWorkspaceRunnable(new Runnable() {
            @Override
            public void run() {
                JPanel newPanel = generateRecentOpenPanel(pageModel);
                
                body.remove(recentOpenPanel);
                recentOpenPanel = newPanel;
                body.add(recentOpenPanel, BorderLayout.SOUTH);
                validate();
                repaint();
            }
        });
    }
    
    @NotNull
    private static JPanel createHeader() {
        
        // Header
        UILabel label = new UILabel(Toolkit.i18nText("Fine-Design_Startup_Page_Select_Workspace"));
        Font font = label.getFont();
        Font titleFont = font.deriveFont(font.getStyle(), TITLE_FONT_SIZE);
        label.setFont(titleFont);
        JPanel headerPanel = new JPanel();
        LayoutManager centerFlowLayout = FRGUIPaneFactory.createCenterFlowLayout();
        headerPanel.setLayout(centerFlowLayout);
        headerPanel.add(label);
        headerPanel.setBackground(new Color(0, 0, 0, 0));
        return headerPanel;
    }
    
    /**
     * 1-mac启动时全屏
     * 2-windows 则居中处理
     */
    private void setFullScreen() {
    
        if (OperatingSystem.isMacos()) {
            this.setLocation(0, 0);
            this.setSize(SCREEN_SIZE.width, SCREEN_SIZE.height);
        } else {
            GUICoreUtils.setWindowFullScreen(this);
        }
    }
    
    private void addDefaultListeners() {
    
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                DesignerExiter.getInstance().execute();
            }
        });
    }
    
    private void setDefaultTitle() {
    
        StringBuilder sb = new StringBuilder();
        sb.append(ProductConstants.APP_NAME);
        sb.append(" ");
        sb.append(GeneralUtils.getVersion());
        sb.append(" ");
        sb.append(ProductConstants.BRANCH);
        sb.append(" ");
        sb.append(Toolkit.i18nText("Fine-Design_Startup_Page_Title"));
        setTitle(sb.toString());
    }
    
    private void patchUIAction(StartupPageModel pageModel) {
        
        Runnable selectAndOpenLastTemplateRunnable = pageModel.getOpenLastTemplateRunnable();
        pageModel.setOpenLastTemplateRunnable(() -> {
            enterWorkspace(selectAndOpenLastTemplateRunnable);
        });
        
        Runnable createNewTemplateRunnable = pageModel.getCreateNewTemplateRunnable();
        pageModel.setCreateNewTemplateRunnable(() -> {
            enterWorkspace(createNewTemplateRunnable);
        });
        
        Runnable openEmptyTemplateRunnable = pageModel.getOpenEmptyTemplateRunnable();
        pageModel.setOpenEmptyTemplateRunnable(() -> {
            enterWorkspace(openEmptyTemplateRunnable);
        });
    }
    
    private void enterWorkspace(Runnable action) {
    
        UIUtil.invokeAndWaitIfNeeded(() -> {
    
            // 必须直接初始化
            // 见 https://work.fineres.com/browse/REPORT-85293
            StartupLoadingPanel loadingPanel = new StartupLoadingPanel(this);
            loadingPanel.show();
            setEnabled(false);
    
            SwingWorker<Void, Void> task = new SwingWorker<Void, Void>() {
                @Override
                protected Void doInBackground() throws Exception {
                    action.run();
                    return null;
                }
        
                @Override
                protected void done() {
            
                    try {
                        Void result = get();
                        setVisible(false);
                    } catch (Exception e) {
                        // 处理错误
                        UIUtil.invokeLaterIfNeeded(() -> {
                            UIExpandDialog.Builder()
                                    .owner(StartupPageWindow.this)
                                    .title(Toolkit.i18nText("Fine-Design_Basic_Remote_Env_Try"))
                                    .message(Toolkit.i18nText("Fine-Design_Basic_Connection_Failed"))
                                    .messageType(UIExpandDialog.WARNING_MESSAGE)
                                    .detail(e.getMessage())
                                    .expand(true)
                                    .modal(false)
                                    .build()
                                    .setVisible(true);
                            setEnabled(true);
                        });
                        FineLoggerFactory.getLogger().error(e.getMessage(), e);
                        StartErrorMessageCollector.getInstance().asyncRecord(DesignerErrorMessage.UNEXCEPTED_START_FAILED.getId(),
                                DesignerErrorMessage.UNEXCEPTED_START_FAILED.getMessage(),
                                e.getMessage());
                    } finally {
                        loadingPanel.hide();
                    }
                }
            };
            task.execute();
        });
    }
    
    private JPanel generateRecentOpenPanel(StartupPageModel pageModel) {
    
        JPanel recentOpenPanel = new JPanel() {
            @Override
            protected void paintComponent(Graphics g) {
                Graphics2D g2d = (Graphics2D) g;
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                g2d.setColor(Color.WHITE);
                g2d.fillRoundRect(0, 0, getWidth(), getHeight(), StartupPageConstants.ARC_DIAMETER, StartupPageConstants.ARC_DIAMETER);
            }
        };
        recentOpenPanel.setLayout(new BorderLayout());
        recentOpenPanel.setBorder(BorderFactory.createEmptyBorder(25, 25, 25, 6));
        
        StartupWorkspaceBean workspaceInfo = pageModel.getSelectWorkspaceInfo();
        JPanel workspaceWrapperYPanel = new JPanel();
        workspaceWrapperYPanel.setName("workspace-wrapper");
        {
            workspaceWrapperYPanel.setLayout(new VerticalFlowLayout());
            
            JPanel workspaceWrapperXPanel = new JPanel();
            workspaceWrapperXPanel.setLayout(new FlowLayout());
            workspaceWrapperXPanel.setBorder(BorderFactory.createEmptyBorder());
            
            JPanel workspacePanel = new JPanel();
            workspacePanel.setLayout(new BorderLayout(0, 15));
            
            UILabel workspaceIcon = new UILabel(StartupPageUtil.getIcon4RecentAreaByWorkspace(workspaceInfo));
            workspacePanel.add(workspaceIcon, BorderLayout.NORTH);
            
            UILabel nameLabel = new UILabel(workspaceInfo.getName());
            nameLabel.setHorizontalAlignment(SwingConstants.CENTER);
            workspacePanel.add(nameLabel, BorderLayout.SOUTH);
            workspaceWrapperXPanel.add(workspacePanel);
            Dimension preferredSize = workspaceWrapperXPanel.getPreferredSize();
            workspaceWrapperXPanel.setPreferredSize(new Dimension(WORKSPACE_PANEL_WIDTH, (int) preferredSize.getHeight()));
            
            workspaceWrapperYPanel.add(workspaceWrapperXPanel);
        }
        recentOpenPanel.add(workspaceWrapperYPanel, BorderLayout.WEST);
        
        JPanel separatorPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
        {
            JSeparator sep = new JSeparator();
            sep.setOrientation(JSeparator.VERTICAL);
            sep.setForeground(SEP_COLOR);
            separatorPanel.add(sep, BorderLayout.CENTER);
        }
        recentOpenPanel.add(separatorPanel, BorderLayout.CENTER);
        
        JComponent recentOpenGroupPanel = generateRecentOpenGroupPanel(pageModel, workspaceInfo);
        recentOpenPanel.add(recentOpenGroupPanel, BorderLayout.EAST);
        
        ColorUtils.syncBackground(recentOpenPanel, Color.WHITE);
        
        Dimension preferredSize = recentOpenPanel.getPreferredSize();
        recentOpenPanel.setPreferredSize(new Dimension(StartupPageConstants.CONTENT_WIDTH, (int) preferredSize.getHeight()));
    
        JPanel recentOpenWrapperPanel = new JPanel();
        recentOpenWrapperPanel.setName("recentOpenWrapper");
        recentOpenWrapperPanel.setLayout(new BorderLayout(0, 0));
        recentOpenWrapperPanel.setBorder(new EmptyBorder(0, 0, 0, 20));
        recentOpenWrapperPanel.add(recentOpenPanel, BorderLayout.CENTER);
        
        ColorUtils.syncBackgroundIfAbsent(recentOpenWrapperPanel, new Color(0,0,0,0), ThemeUtils.BACK_COLOR);
        return recentOpenWrapperPanel;
    }
    
    @NotNull
    private JComponent generateRecentOpenGroupPanel(StartupPageModel pageModel, StartupWorkspaceBean workspaceInfo) {
        
        JPanel recentOpenGroupPanel = new JPanel();
        Map<String, List<String>> recentFilesMap = pageModel.getRecentFilesMap();
        
        boolean needScroll = false;
        double itemHeight = 0.0d;
        if (!CollectionUtils.isEmpty(recentFilesMap)) {
            String name = workspaceInfo.getName();
            List<String> recentFiles = recentFilesMap.get(name);
            if (!CollectionUtils.isEmpty(recentFiles)) {
                recentOpenGroupPanel.setLayout(new GridLayout(recentFiles.size(), 1, 50, 5));
                needScroll = recentFiles.size() > RECENT_FILE_LIMIT;
                for (String recentFile : recentFiles) {
                    JPanel recentItemPanel = new JPanel();
                    recentItemPanel.setLayout(new FlowLayout(FlowLayout.LEFT, ITEM_VERTICAL_GAP, 0));
                    recentItemPanel.add(new UILabel(IconUtils.readIcon("/com/fr/design/standard/system/cpt")));
                    UILabel recentFileLabel = new UILabel(recentFile);
                    Color recentFileLabelForeground = recentFileLabel.getForeground();
                    recentItemPanel.add(recentFileLabel);
                    recentItemPanel.addMouseListener(new MouseAdapter() {
                        @Override
                        public void mouseEntered(MouseEvent e) {
                            recentFileLabel.setForeground(HOVER_COLOR);
                            StartupPageUtil.repaintAll(recentOpenGroupPanel);
                        }
                
                        @Override
                        public void mouseExited(MouseEvent e) {
                            recentFileLabel.setForeground(recentFileLabelForeground);
                            StartupPageUtil.repaintAll(recentOpenGroupPanel);
                        }
                
                        @Override
                        public void mouseClicked(MouseEvent e) {
                            doOpenLastTemplateAction(recentFile, pageModel);
                        }
                    });
                    Dimension preferredSize = recentItemPanel.getPreferredSize();
                    itemHeight = preferredSize.getHeight();
                    recentOpenGroupPanel.add(recentItemPanel);
                }
            }
        }
        Dimension preferredSize = recentOpenGroupPanel.getPreferredSize();
        recentOpenGroupPanel.setPreferredSize(new Dimension(GROUP_WIDTH, (int) preferredSize.getHeight()));
        
        if (needScroll) {
            int scrollHeight = (int) Math.round(itemHeight * RECENT_FILE_LIMIT + ITEM_VERTICAL_GAP * (RECENT_FILE_LIMIT));
            UIScrollPane scrollPane = new UIScrollPane(recentOpenGroupPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
            scrollPane.setBorder(new EmptyBorder(0, 0, 0, 0));
            scrollPane.setPreferredSize(new Dimension(GROUP_WIDTH, scrollHeight));
            return scrollPane;
        }
        return recentOpenGroupPanel;
    }
    
    private StartupPageWorkspacePanel generateWorkspacePanel(StartupPageModel pageModel) {
    
        StartupPageWorkspacePanel startupPageWorkspacePanel = new StartupPageWorkspacePanel(pageModel);
        ColorUtils.syncBackgroundIfAbsent(startupPageWorkspacePanel, new Color(0, 0, 0, 0), ThemeUtils.BACK_COLOR);
        return startupPageWorkspacePanel;
    }
    
    protected LayoutManager getCenterLayout(JComponent centerBody) {
        
        return FRGUIPaneFactory.createCenterLayout(centerBody);
    }
    
    private void doOpenLastTemplateAction(String recentFile, StartupPageModel pageModel) {
        
        DesignerEnvManager.getEnvManager().setLastOpenFile(recentFile);
        pageModel.getOpenLastTemplateRunnable().run();
    
        DesignerMetrics designerMetrics = DesignerStartupContext.getInstance().getDesignerMetrics();
        designerMetrics.getStatistic().recordOpenLastTemplate(recentFile);
    }
    
}