package com.huangzj.protoplugin;

import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.ui.ValidationInfo;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.components.JBScrollPane;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import org.jetbrains.annotations.Nullable;

public class GenerateCmdDialog extends DialogWrapper {

    private final Project project;
    private final ProtoParseResult parseResult;
    private final String cmdRpcFullText;
    private final Map<Integer, String> pbServiceByNumber;
    private final List<JCheckBox> checkBoxes = new ArrayList<>();
    private final TextFieldWithBrowseButton outputDirField = new TextFieldWithBrowseButton();

    public GenerateCmdDialog(
            @Nullable Project project,
            ProtoParseResult parseResult,
            String cmdRpcFullText,
            Map<Integer, String> pbServiceByNumber) {
        super(project);
        this.project = project;
        this.parseResult = parseResult;
        this.cmdRpcFullText = cmdRpcFullText;
        this.pbServiceByNumber = pbServiceByNumber;
        setTitle("Proto转Java");
        init();
    }

    @Override
    protected JComponent createCenterPanel() {
        JPanel root = new JPanel(new BorderLayout(8, 8));

        String jp = parseResult.getJavaPackageOption();
        JLabel hint =
                new JLabel("<html>proto <code>java_package</code>: <b>"
                        + (jp != null ? jp : "(未解析到 option java_package)")
                        + "</b><br/>勾选要生成的 RPC；输出目录建议选模块下 <code>src/main/java/.../cmd/cmds</code>。</html>");
        root.add(hint, BorderLayout.NORTH);

        JPanel listPanel = new JPanel();
        listPanel.setLayout(new BoxLayout(listPanel, BoxLayout.Y_AXIS));
        for (RpcMethodInfo rpc : parseResult.getRpcMethods()) {
            JCheckBox cb = new JCheckBox(rpc.toString(), true);
            cb.putClientProperty("rpc", rpc);
            checkBoxes.add(cb);
            listPanel.add(cb);
            listPanel.add(Box.createVerticalStrut(4));
        }
        JBScrollPane scroll = new JBScrollPane(listPanel);
        scroll.setPreferredSize(new Dimension(560, 220));
        root.add(scroll, BorderLayout.CENTER);

        JPanel south = new JPanel(new BorderLayout(4, 4));
        south.add(new JLabel("输出目录:"), BorderLayout.WEST);
        FileChooserDescriptor desc = FileChooserDescriptorFactory.createSingleFolderDescriptor();
        desc.setTitle("选择生成 Java 的根目录（通常为 .../cmd/cmds）");
        outputDirField.addBrowseFolderListener("选择目录", null, project, desc);
        south.add(outputDirField, BorderLayout.CENTER);
        root.add(south, BorderLayout.SOUTH);

        return root;
    }

    @Nullable
    @Override
    protected ValidationInfo doValidate() {
        String path = outputDirField.getText().trim();
        if (path.isEmpty()) {
            return new ValidationInfo("请选择输出目录", outputDirField);
        }
        VirtualFile dir = LocalFileSystem.getInstance().findFileByPath(path);
        if (dir == null || !dir.isDirectory()) {
            return new ValidationInfo("输出路径不是有效目录", outputDirField);
        }
        String pkg = PackageInference.inferPackage(dir);
        if (pkg.isEmpty()) {
            return new ValidationInfo(
                    "无法推断 Java 包名：请选择位于 .../src/main/java/<包路径>/ 下的目录。", outputDirField);
        }
        List<RpcMethodInfo> sel = getSelectedRpcs();
        if (sel.isEmpty()) {
            return new ValidationInfo("请至少勾选一条 RPC");
        }
        for (RpcMethodInfo rpc : sel) {
            List<String> methods =
                    ProtoEnumResolver.orderedMethodConstantNames(cmdRpcFullText, rpc.getServiceIndex());
            if (rpc.getRpcIndexInService() >= methods.size()) {
                return new ValidationInfo(
                        "RPC "
                                + rpc.getRpcName()
                                + " 在 service "
                                + rpc.getServiceIndex()
                                + " 中为第 "
                                + (rpc.getRpcIndexInService() + 1)
                                + " 条，但 proto 中 Service"
                                + rpc.getServiceIndex()
                                + "_Method 可用枚举项不足（请检查 Method 定义顺序与 RPC 顺序是否一致）。");
            }
        }
        return null;
    }

    public List<RpcMethodInfo> getSelectedRpcs() {
        List<RpcMethodInfo> list = new ArrayList<>();
        for (JCheckBox cb : checkBoxes) {
            if (cb.isSelected()) {
                list.add((RpcMethodInfo) cb.getClientProperty("rpc"));
            }
        }
        return list;
    }

    public VirtualFile getOutputDirectory() {
        String path = outputDirField.getText().trim();
        return LocalFileSystem.getInstance().findFileByPath(path);
    }

    public String getOutputPackage() {
        VirtualFile dir = getOutputDirectory();
        return PackageInference.inferPackage(dir);
    }

    public String getProtoJavaPackage() {
        String p = parseResult.getJavaPackageOption();
        return p != null ? p : "com.huangzj.cmd.gen";
    }

    public String resolvePbServiceEnumName(RpcMethodInfo rpc) {
        return ProtoEnumResolver.resolvePbServiceConstant(pbServiceByNumber, rpc.getServiceIndex());
    }

    public String resolveMethodEnumConstant(RpcMethodInfo rpc) {
        List<String> names =
                ProtoEnumResolver.orderedMethodConstantNames(cmdRpcFullText, rpc.getServiceIndex());
        return names.get(rpc.getRpcIndexInService());
    }
}
