package xyz.wbsite.dbtool.javafx.ctrl;

import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.util.Callback;
import javafx.util.converter.DefaultStringConverter;
import xyz.wbsite.dbtool.javafx.po.Api;
import xyz.wbsite.dbtool.javafx.po.ApiMethod;
import xyz.wbsite.dbtool.javafx.tool.ApiClassReader;
import xyz.wbsite.dbtool.javafx.tool.Dialog;
import xyz.wbsite.dbtool.javafx.tool.Tool;
import xyz.wbsite.dbtool.javafx.view.DBCheckBoxTableCell;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class OptionApiController {

    @FXML
    private TextField modulePath;
    @FXML
    private TextField apiPath;
    @FXML
    private Button selectModulePath;
    @FXML
    private Button selectApiPath;
    @FXML
    private Button start;
    @FXML
    private Button cancel;
    @FXML
    private CheckBox All;
    @FXML
    private CheckBox create;
    @FXML
    private CheckBox delete;
    @FXML
    private CheckBox update;
    @FXML
    private CheckBox find;
    @FXML
    private CheckBox search;
    @FXML
    private CheckBox get;
    @FXML
    private TableView apis;
    @FXML
    private List<Api> data = new ArrayList<>();

    private List<String> domainList = new ArrayList<>();

    public Button getSelectModulePath() {
        return selectModulePath;
    }

    public void setSelectModulePath(Button selectModulePath) {
        this.selectModulePath = selectModulePath;
    }

    public Button getSelectSdkPath() {
        return selectApiPath;
    }

    public void setSelectSdkPath(Button selectSdkPath) {
        this.selectApiPath = selectSdkPath;
    }

    public List<Api> getData() {
        return data;
    }

    public CheckBox getSearch() {
        return search;
    }

    public CheckBox getAll() {
        return All;
    }

    public void setAll(CheckBox all) {
        All = all;
    }

    public void setSearch(CheckBox search) {
        this.search = search;
    }

    public CheckBox getCreate() {
        return create;
    }

    public void setCreate(CheckBox create) {
        this.create = create;
    }

    public CheckBox getDelete() {
        return delete;
    }

    public void setDelete(CheckBox delete) {
        this.delete = delete;
    }

    public CheckBox getUpdate() {
        return update;
    }

    public void setUpdate(CheckBox update) {
        this.update = update;
    }

    public CheckBox getFind() {
        return find;
    }

    public void setFind(CheckBox find) {
        this.find = find;
    }

    public CheckBox getGet() {
        return get;
    }

    public void setGet(CheckBox get) {
        this.get = get;
    }

    public void setData(List<Api> data) {
        this.data = data;
    }

    public TextField getModulePath() {
        return modulePath;
    }

    public void setModulePath(TextField modulePath) {
        this.modulePath = modulePath;
    }

    public TextField getApiPath() {
        return apiPath;
    }

    public void setApiPath(TextField apiPath) {
        this.apiPath = apiPath;
    }

    public Button getStart() {
        return start;
    }

    public void setStart(Button start) {
        this.start = start;
    }

    public Button getCancel() {
        return cancel;
    }

    public void setCancel(Button cancel) {
        this.cancel = cancel;
    }

    public TableView getApis() {
        return apis;
    }

    public void setApis(TableView apis) {
        this.apis = apis;
    }

    public List<String> getDomainList() {
        return domainList;
    }

    public void setDomainList(List<String> domainList) {
        this.domainList = domainList;
    }

    public void load() {
        File moduleFile = new File(modulePath.getText());

        data.clear();
        if (moduleFile.exists()) {

            List<File> apiPath = Tool.findApi(moduleFile, "api");

            if (apiPath.size() == 0) {
                return;
            }

            String absolutePath = apiPath.get(0).getAbsolutePath();
            String separator = Tool.replaceSeparator(absolutePath, "#");

            Pattern compile = Pattern.compile(".*src#main#java#(.*)#action#api");
            Matcher matcher = compile.matcher(separator);
            if (matcher.find()) {
                String group = matcher.group(1);
                String[] split = group.split("#");
                for (String s : split) {
                    domainList.add(s);
                }
            }

            for (File file : apiPath.get(0).listFiles()) {
                String module = file.getName();
                for (File tar : file.listFiles()) {
                    try {
                        String target = tar.getName().replaceAll("Api", "").replaceAll(".java", "");
                        ApiClassReader apiClassReader = new ApiClassReader(tar);

                        for (ApiMethod apiMethod : apiClassReader.getMethodList()) {
                            Api api = new Api();
                            api.setModule(module);
                            api.setTarget(target);
                            api.setRequest(apiMethod.getRequest());
                            api.setResponse(apiMethod.getResponse());
                            api.setMethod(apiMethod.getMethod());

                            List<File> reqFiles = Tool.findRequest(moduleFile, apiMethod.getRequest() + ".java");
                            if (reqFiles.size() == 0) {
                                api.setError(api.getError() + "未找到请求");
                            } else if (reqFiles.size() > 1) {
                                api.setError(api.getError() + "找到多个请求");
                            } else {
                                api.setRequestFile(reqFiles.get(0));
                                //查找依赖ent
                                List<String> entities = findEntities(reqFiles.get(0));
                                for (String entity : entities) {
                                    api.getDepEnt().add(entity);
                                }

                                //查找依赖req
                                List<String> reqss = findReq(reqFiles.get(0));
                                for (String string : reqss) {
                                    api.getDepReq().add(string);
                                }
                            }

                            List<File> rspfiles = Tool.findResponse(moduleFile, apiMethod.getResponse() + ".java");
                            if (rspfiles.size() == 0) {
                                api.setError(api.getError() + "未找到响应");
                            } else if (rspfiles.size() > 1) {
                                api.setError(api.getError() + "找到多个响应");
                            } else {
                                api.setResponseFile(rspfiles.get(0));
                                //查找依赖ent
                                List<String> entities = findEntities(rspfiles.get(0));
                                for (String entity : entities) {
                                    api.getDepEnt().add(entity);
                                }

                                //查找依赖req
                                List<String> reqss = findReq(rspfiles.get(0));
                                for (String string : reqss) {
                                    api.getDepReq().add(string);
                                }
                            }

                            api.setCheck(true);
                            data.add(api);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }

            initData();
        }
    }

    public List<String> findEntities(File file) {
        ArrayList<String> strings = new ArrayList<>();
        InputStreamReader read = null;//考虑到编码格式
        try {
            read = new InputStreamReader(new FileInputStream(file), "UTF-8");
            BufferedReader bufferedReader = new BufferedReader(read);
            String line = null;
            while ((line = bufferedReader.readLine()) != null) {
                //指定字符串判断处
                if (line.contains(".ent.")) {
                    Pattern compile = Pattern.compile(".*\\.ent\\.(.*);");

                    Matcher matcher = compile.matcher(line);

                    if (matcher.find()) {
                        String group = matcher.group(1);
                        strings.add(group);
//                        System.out.println(group);
                    }
                }
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return strings;
    }

    public List<String> findReq(File file) {
        ArrayList<String> strings = new ArrayList<>();
        InputStreamReader read = null;//考虑到编码格式
        try {
            read = new InputStreamReader(new FileInputStream(file), "UTF-8");
            BufferedReader bufferedReader = new BufferedReader(read);
            String line = null;
            Pattern compile1 = Pattern.compile(".*private\\s([a-zA-Z_]*Request)\\s[a-zA-Z_]*Request;.*");
            Pattern compile2 = Pattern.compile(".*private\\sList<([a-zA-Z_]*Request)>\\s[a-zA-Z_]*Requests;.*");
            Pattern compile3 = Pattern.compile(".*private\\sList<([a-zA-Z_]*Request)>\\s[a-zA-Z_]*RequestList;.*");


            while ((line = bufferedReader.readLine()) != null) {
                //携带一个Request
                if (line.matches(".*private\\s([a-zA-Z_]*Request)\\s[a-zA-Z_]*Request;.*")) {
                    Matcher matcher = compile1.matcher(line);

                    if (matcher.find()) {
                        String group = matcher.group(1);

                        strings.add(group);
                        System.out.println(group);
                    }
                }
                //携带一个List<*Request> *Requests;
                if (line.matches(".*private\\sList<([a-zA-Z_]*Request)>\\s[a-zA-Z_]*Requests;.*")) {
                    Matcher matcher = compile2.matcher(line);

                    if (matcher.find()) {
                        String group = matcher.group(1);

                        strings.add(group);
                        System.out.println(group);
                    }
                }
                //携带一个List<*Request> *RequestList;
                if (line.matches(".*private\\sList<([a-zA-Z_]*Request)>\\s[a-zA-Z_]*RequestList;.*")) {
                    Matcher matcher = compile3.matcher(line);

                    if (matcher.find()) {
                        String group = matcher.group(1);

                        strings.add(group);
                        System.out.println(group);
                    }
                }
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return strings;
    }

    public void initData() {
        apis.setEditable(true);
        apis.setSortPolicy(new Callback<TableView, Boolean>() {
            @Override
            public Boolean call(TableView param) {
                //禁止点击列头排序
                return false;
            }
        });
        ObservableList<TableColumn> columns = apis.getColumns();
        columns.get(0).setCellValueFactory(new PropertyValueFactory("check"));
        columns.get(0).setCellFactory(new Callback<TableColumn, TableCell>() {
            @Override
            public TableCell call(TableColumn param) {
                final DBCheckBoxTableCell checkBoxTableCell = new DBCheckBoxTableCell();
                DBCheckBoxTableCell.sCallback sCallback = checkBoxTableCell.new sCallback() {
                    @Override
                    public ObservableValue<Boolean> call(Integer param) {
                        super.call(param);
                        if (data.get(param).isCheck()) {
                            return new SimpleBooleanProperty(true);
                        } else {
                            return new SimpleBooleanProperty(false);
                        }
                    }
                };
                checkBoxTableCell.setSelectedStateCallback(sCallback);
                checkBoxTableCell.setOnChangeListener(new ChangeListener<Boolean>() {
                    @Override
                    public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                        int param1 = checkBoxTableCell.getParam();
                        Api api = data.get(param1);
                        api.setCheck(newValue);
                    }
                });
                return checkBoxTableCell;
            }
        });
        columns.get(1).setCellValueFactory(new PropertyValueFactory("module"));
        columns.get(1).setCellFactory(new Callback<TableColumn, TableCell>() {
            @Override
            public TableCell call(TableColumn param) {
                TextFieldTableCell textFieldTableCell = new TextFieldTableCell(new DefaultStringConverter()) {
                    @Override
                    public void updateItem(Object item, boolean empty) {
                        super.updateItem(item, empty);
                    }
                };

                textFieldTableCell.setEditable(false);
                return textFieldTableCell;
            }
        });
        columns.get(2).setCellValueFactory(new PropertyValueFactory("target"));
        columns.get(2).setCellFactory(new Callback<TableColumn, TableCell>() {
            @Override
            public TableCell call(TableColumn param) {
                TextFieldTableCell textFieldTableCell = new TextFieldTableCell(new DefaultStringConverter()) {
                    @Override
                    public void updateItem(Object item, boolean empty) {
                        super.updateItem(item, empty);
                    }
                };

                textFieldTableCell.setEditable(false);
                return textFieldTableCell;
            }
        });
        columns.get(3).setCellValueFactory(new PropertyValueFactory("method"));
        columns.get(3).setCellFactory(new Callback<TableColumn, TableCell>() {
            @Override
            public TableCell call(TableColumn param) {
                TextFieldTableCell textFieldTableCell = new TextFieldTableCell(new DefaultStringConverter()) {
                    @Override
                    public void updateItem(Object item, boolean empty) {
                        super.updateItem(item, empty);
                    }
                };
                textFieldTableCell.setEditable(false);
                return textFieldTableCell;
            }
        });
        columns.get(4).setCellValueFactory(new PropertyValueFactory("error"));
        columns.get(4).setCellFactory(new Callback<TableColumn, TableCell>() {
            @Override
            public TableCell call(TableColumn param) {
                TextFieldTableCell textFieldTableCell = new TextFieldTableCell(new DefaultStringConverter()) {
                    @Override
                    public void updateItem(Object item, boolean empty) {
                        super.updateItem(item, empty);
                    }
                };
                textFieldTableCell.setEditable(false);
                return textFieldTableCell;
            }
        });
        columns.get(5).setCellValueFactory(new PropertyValueFactory("request"));
        columns.get(5).setCellFactory(new Callback<TableColumn, TableCell>() {
            @Override
            public TableCell call(TableColumn param) {
                TextFieldTableCell textFieldTableCell = new TextFieldTableCell(new DefaultStringConverter()) {
                    @Override
                    public void updateItem(Object item, boolean empty) {
                        super.updateItem(item, empty);
                    }
                };
                textFieldTableCell.setEditable(false);
                return textFieldTableCell;
            }
        });
        columns.get(6).setCellValueFactory(new PropertyValueFactory("response"));
        columns.get(6).setCellFactory(new Callback<TableColumn, TableCell>() {
            @Override
            public TableCell call(TableColumn param) {
                TextFieldTableCell textFieldTableCell = new TextFieldTableCell(new DefaultStringConverter()) {
                    @Override
                    public void updateItem(Object item, boolean empty) {
                        super.updateItem(item, empty);
                    }
                };
                textFieldTableCell.setEditable(false);
                return textFieldTableCell;
            }
        });
        ObservableList<Api> ObservableList = FXCollections.observableArrayList();
        ObservableList.addAll(data);
        apis.setItems(ObservableList);
    }
}
