package cn.fantasticmao.ycy.intellij.plugin.config;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserDialog;
import com.intellij.openapi.fileChooser.FileChooserFactory;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.table.JBTable;
import com.intellij.util.ui.EditableModel;

import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 插件设置页面的表格对象
 *
 * @author maomao
 * @version 1.3
 * @since 2019-05-05
 */
public class PluginSettingTable extends JBTable {
    private static final Logger LOG = Logger.getInstance(PluginSettingTable.class);

    /**
     * 序号列
     */
    private static final int ORDER_COLUMN = 0;

    /**
     * 图片 URL 列
     */
    private static final int URL_COLUMN = 1;

    public PluginSettingTable(List<String> defaultImageUrlList) {
        super(new ModelAdapter(defaultImageUrlList));
        super.setStriped(true);

        final TableColumnModel columnModel = getColumnModel();
        final TableColumn orderColumn = columnModel.getColumn(ORDER_COLUMN);
        orderColumn.setPreferredWidth(20);

        final TableColumn urlColumn = columnModel.getColumn(URL_COLUMN);
        urlColumn.setPreferredWidth(280);
    }

    /**
     * 获取表格的 {@link javax.swing.table.TableModel}
     *
     * <p>实现 {@link com.intellij.util.ui.EditableModel} 表示表格是可编辑的</p>
     *
     * @see com.intellij.ui.ToolbarDecorator#createDecorator(JTable)
     */
    @Override
    public ModelAdapter getModel() {
        return (ModelAdapter) super.getModel();
    }

    /**
     * 重置表格数据
     */
    public void resetTableList() {
        this.getModel().setRowsData(DefaultConfig.REMIND_IMAGE_LIST);
        LOG.info("reset image url list to default");
    }

    /**
     * 获取表格数据
     */
    public List<String> getTableList() {
        List<String> imageList = this.getModel().getRowsData();
        LOG.info("get image url list: " + imageList);
        return imageList;
    }

    /**
     * 设置表格数据
     */
    public void setTableList(List<String> imageList) {
        this.getModel().setRowsData(imageList);
        LOG.info("set image url list to: " + imageList);
    }

    /**
     * 插件设置页面的表格对象的 {@link javax.swing.table.TableModel}
     *
     * <p>实现 {@link com.intellij.util.ui.EditableModel} 表示表格是可编辑的</p>
     */
    private static class ModelAdapter extends AbstractTableModel implements EditableModel {
        private static final Logger LOG = Logger.getInstance(ModelAdapter.class);

        /**
         * 图片 URL 列表数据
         */
        private final List<String> imageUrlList;

        public ModelAdapter(List<String> defaultImageUrlList) {
            // 复制表格数据(使用深拷贝模式),避免修改默认图片配置
            this.imageUrlList = new ArrayList<>(defaultImageUrlList.size());
            this.imageUrlList.addAll(defaultImageUrlList);
        }

        /**
         * 获取总行数
         */
        @Override
        public int getRowCount() {
            return imageUrlList.size();
        }

        /**
         * 获取总列数
         */
        @Override
        public int getColumnCount() {
            return 2;
        }

        /**
         * 根据列号,获取默认列名
         */
        @Override
        public String getColumnName(int column) {
            return column == ORDER_COLUMN ? "序号" : "图片 URL";
        }

        /**
         * 设置单元格对象的 {@link java.lang.Class}
         */
        @Override
        public Class<?> getColumnClass(int columnIndex) {
            return String.class;
        }

        /**
         * 是否可以编辑单元格内容
         */
        @Override
        public boolean isCellEditable(int rowIndex, int columnIndex) {
            return false;
        }

        /**
         * 根据单元格坐标,获取单元格内容
         */
        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            return columnIndex == ORDER_COLUMN ? String.valueOf(rowIndex) : imageUrlList.get(rowIndex);
        }

        /**
         * 添加表格行
         */
        @Override
        public void addRow() {
            FileChooserDescriptor descriptor = PluginSettingConfig.IMAGE_FILE_CHOOSER;
            FileChooserDialog dialog = FileChooserFactory.getInstance().createFileChooser(descriptor, null, null);
            VirtualFile[] files = dialog.choose(null);
            List<String> chosenImageUrlList = Stream.of(files)
                .map(imageFile -> {
                    try {
                        return VfsUtil.toUri(imageFile).toURL().toString();
                    } catch (MalformedURLException e) {
                        LOG.error("parse the image \"" + imageFile.getName() + "\" to URL error", e);
                        return null;
                    }
                })
                .filter(Objects::nonNull)
                .filter(imageUrl -> !imageUrlList.contains(imageUrl))
                .collect(Collectors.toList());
            if (chosenImageUrlList.size() != 0) {
                imageUrlList.addAll(chosenImageUrlList);
                LOG.info("add rows: " + chosenImageUrlList);
                super.fireTableRowsInserted(imageUrlList.size() - 1 - files.length, imageUrlList.size() - 1);
            } else {
                LOG.info("choose no files");
            }
        }

        /**
         * 交换表格行
         */
        @Override
        public void exchangeRows(int oldIndex, int newIndex) {
            final String oldImgUrl = imageUrlList.get(oldIndex);
            final String newImgUrl = imageUrlList.get(newIndex);
            imageUrlList.set(oldIndex, newImgUrl);
            imageUrlList.set(newIndex, oldImgUrl);
            LOG.info(String.format("exchange rows index: %d -> %d", oldIndex, newIndex));
            super.fireTableRowsUpdated(Math.min(oldIndex, newIndex), Math.max(oldIndex, newIndex));
        }

        /**
         * 是否可以交换表格行
         */
        @Override
        public boolean canExchangeRows(int oldIndex, int newIndex) {
            return true;
        }

        /**
         * 删除表格行
         */
        @Override
        public void removeRow(int idx) {
            imageUrlList.remove(idx);
            LOG.info("remove row index: " + idx);
            super.fireTableRowsDeleted(idx, idx);
        }

        /**
         * 获取表格行数据
         */
        public List<String> getRowsData() {
            List<String> rows = Collections.unmodifiableList(new ArrayList<>(imageUrlList));
            LOG.info("get rows data: " + rows);
            return rows;
        }

        /**
         * 设置表格行数据
         */
        public void setRowsData(List<String> list) {
            imageUrlList.clear();
            imageUrlList.addAll(list);
            LOG.info("set rows data: " + list);
            super.fireTableDataChanged();
        }
    }
}