package com.actiontech.dble.manager;

import com.actiontech.dble.route.parser.util.Pair;
import com.actiontech.dble.services.manager.dump.parse.InsertParser;
import com.actiontech.dble.services.manager.dump.parse.InsertQueryPos;
import org.junit.Assert;
import org.junit.Test;

import java.util.List;

public class SplitCSVTest {
    @Test
    public void test1() {
        String sql = "replace  into table1(col1,column2) values(1,'3'),(2,'5'),(3,';,');";
        char[] sqlArray = sql.toCharArray();
        InsertParser obj = new InsertParser(sql);
        InsertQueryPos pos = obj.parseStatement();
        Assert.assertEquals(0, pos.getQueryRange().getKey().intValue());
        Assert.assertEquals(sql.length(), pos.getQueryRange().getValue().intValue());
        Assert.assertTrue(pos.isReplace());
        Assert.assertFalse(pos.isIgnore());
        Assert.assertEquals("table1", pos.getTableName());
        Assert.assertEquals("col1,column2", getSubString(sqlArray, pos.getColumnRange()));
        List<Pair<Integer, Integer>> valueRange = pos.getValuesRange();
        // first value
        Assert.assertEquals("1,'3'", getSubString(sqlArray, valueRange.get(0)));
        // 3nd value
        Assert.assertEquals("3,';,'", getSubString(sqlArray, valueRange.get(2)));
        // 3nd value ,2th col
        Pair<Integer, Integer> valueItemRange = pos.getValueItemsRange().get(2).get(1);
        Assert.assertEquals("';,'", getSubString(sqlArray, valueItemRange));

    }

    @Test
    public void test2() {
        String sql = "insert ignore into table1(col1,column2) values(1,'3'),(2,'5'),(3,';,');";
        char[] sqlArray = sql.toCharArray();
        InsertParser obj = new InsertParser(sql);
        InsertQueryPos pos = obj.parseStatement();
        Assert.assertEquals(0, pos.getQueryRange().getKey().intValue());
        Assert.assertEquals(sql.length(), pos.getQueryRange().getValue().intValue());
        Assert.assertFalse(pos.isReplace());
        Assert.assertTrue(pos.isIgnore());
        Assert.assertEquals("table1", pos.getTableName());
        Assert.assertEquals("col1,column2", getSubString(sqlArray, pos.getColumnRange()));
        List<Pair<Integer, Integer>> valueRange = pos.getValuesRange();
        // first value
        Assert.assertEquals("1,'3'", getSubString(sqlArray, valueRange.get(0)));
        // 3nd value
        Assert.assertEquals("3,';,'", getSubString(sqlArray, valueRange.get(2)));
        // 3nd value ,2th col
        Pair<Integer, Integer> valueItemRange = pos.getValueItemsRange().get(2).get(1);
        Assert.assertEquals("';,'", getSubString(sqlArray, valueItemRange));

    }

    @Test
    public void test3() {
        String sql = "insert  into table1  values(1,'3'),(2,'5'),(3,';,');";
        char[] sqlArray = sql.toCharArray();
        InsertParser obj = new InsertParser(sql);
        InsertQueryPos pos = obj.parseStatement();
        Assert.assertEquals(0, pos.getQueryRange().getKey().intValue());
        Assert.assertEquals(sql.length(), pos.getQueryRange().getValue().intValue());
        Assert.assertFalse(pos.isReplace());
        Assert.assertFalse(pos.isIgnore());
        Assert.assertEquals("table1", pos.getTableName());
        List<Pair<Integer, Integer>> valueRange = pos.getValuesRange();
        // first value
        Assert.assertEquals("1,'3'", getSubString(sqlArray, valueRange.get(0)));
        // 3nd value
        Assert.assertEquals("3,';,'", getSubString(sqlArray, valueRange.get(2)));
        // 3nd value ,2th col
        Pair<Integer, Integer> valueItemRange = pos.getValueItemsRange().get(2).get(1);
        Assert.assertEquals("';,'", getSubString(sqlArray, valueItemRange));

        Assert.assertEquals(";,", getValueString(sqlArray, valueItemRange));

        Pair<Integer, Integer> valueItemRange1 = pos.getValueItemsRange().get(2).get(0);
        Assert.assertEquals("3", getValueString(sqlArray, valueItemRange1));
    }

    @Test
    public void test4() {
        Assert.assertNotNull(getInsertQueryPos("insert ignore into table1(col1,column2) values(1,'3'),(2,'5'),(3,';,');").getQueryRange());
        Assert.assertNull(getInsertQueryPos("insert ignore into table1(col1,column2) values(1,'3'),(2,'5'),(3,';,')").getQueryRange());
        Assert.assertNull(getInsertQueryPos("insert ignore into table1(col1,column2) values(1,'3'),(2,'5'),(3,';,'").getQueryRange());
        Assert.assertNull(getInsertQueryPos("insert ignore into table1(col1,column2) values(1,'3'),(2,'5'),(3,';").getQueryRange());
        Assert.assertNull(getInsertQueryPos("insert ignore into table1(col1,column2) values(1,").getQueryRange());
        Assert.assertNull(getInsertQueryPos("insert ignore into table1(col1,column2) values").getQueryRange());
        Assert.assertNull(getInsertQueryPos("insert ignore into table1(col1,column2) val").getQueryRange());
        Assert.assertNull(getInsertQueryPos("insert ignore into table1(col1,column2)").getQueryRange());
        Assert.assertNull(getInsertQueryPos("insert ignore into table1(col1,").getQueryRange());
        Assert.assertNull(getInsertQueryPos("insert ignore into table1(col").getQueryRange());
        Assert.assertNull(getInsertQueryPos("insert ignore into table").getQueryRange());
        Assert.assertNull(getInsertQueryPos("insert ignore into ").getQueryRange());
        Assert.assertNull(getInsertQueryPos("insert ignore in ").getQueryRange());
        Assert.assertNull(getInsertQueryPos("insert ignore  ").getQueryRange());
        Assert.assertNull(getInsertQueryPos("insert ign").getQueryRange());
        Assert.assertNull(getInsertQueryPos("insert").getQueryRange());
        Assert.assertNull(getInsertQueryPos("inser"));
    }

    @Test
    public void test5() {
        String s1 = "insert  into table1  values(4,'z'),(5,'y'),(6,'x');\n";
        String s2 = "insert  into table1  values(1,'3'),(2,'5'),(3,';,');";
        String sql = s1 + s2;
        char[] sqlArray = sql.toCharArray();
        InsertParser obj = new InsertParser(sql);
        InsertQueryPos pos1 = obj.parseStatement(); // first time
        InsertQueryPos pos = obj.parseStatement(); //second time
        Assert.assertEquals(s1.length(), pos.getQueryRange().getKey().intValue());
        Assert.assertEquals(sql.length(), pos.getQueryRange().getValue().intValue());
        Assert.assertFalse(pos.isReplace());
        Assert.assertFalse(pos.isIgnore());
        Assert.assertEquals("table1", pos.getTableName());
        List<Pair<Integer, Integer>> valueRange = pos.getValuesRange();
        // first value
        Assert.assertEquals("1,'3'", getSubString(sqlArray, valueRange.get(0)));
        // 3nd value
        Assert.assertEquals("3,';,'", getSubString(sqlArray, valueRange.get(2)));
        // 3nd value ,2th col
        Pair<Integer, Integer> valueItemRange = pos.getValueItemsRange().get(2).get(1);
        Assert.assertEquals("';,'", getSubString(sqlArray, valueItemRange));

        Assert.assertEquals(";,", getValueString(sqlArray, valueItemRange));

        Pair<Integer, Integer> valueItemRange1 = pos.getValueItemsRange().get(2).get(0);
        Assert.assertEquals("3", getValueString(sqlArray, valueItemRange1));
    }

    @Test
    public void test6() {
        String s11 = ");\ninsert  into table1  values(4,'z'),(5,'y'),(6,'x');\n";
        String s12 = "insert  into table1  values(7,'z7'),(8,'8'),(9,'9');\n";
        String s13 = "insert  into table1  value";

        String s21 = "s(1,'3'),(2,'5'),(3,';,');\n";
        String s22 = "insert  into table1  values(10,'10'),(11,'11'),(12,'12');\n";
        String s23 = "insert  into table1  values(13,'13'),(14";
        String s1 = s11 + s12 + s13;
        String s2 = s21 + s22 + s23;

        char[] sqlArray1 = s1.toCharArray();
        char[] sqlArray2 = s2.toCharArray();
        InsertParser obj1 = new InsertParser(s1);
        obj1.findInsert();
        InsertQueryPos tmpPos = obj1.parseStatement();
        int lastEndPos = 0;
        // not insert query or insert not finish
        while (tmpPos != null && tmpPos.getQueryRange() != null) {
            //do something about tmpPos
            lastEndPos = tmpPos.getQueryRange().getValue();
            tmpPos = obj1.parseStatement();
        }

        InsertParser obj2 = new InsertParser(s2);
        // may need loop
        int nextStartPos = obj2.findInsert();

        // cat last end and next start
        char[] sqlArray = genCatChars(sqlArray1, sqlArray2, lastEndPos, nextStartPos);
        String catQuery = new String(sqlArray);

        InsertParser obj = new InsertParser(catQuery);
        InsertQueryPos pos = obj.parseStatement();

        // then do obj2 ... obj2.parseStatement();

        Assert.assertFalse(pos.isReplace());
        Assert.assertFalse(pos.isIgnore());
        Assert.assertEquals("table1", pos.getTableName());
        List<Pair<Integer, Integer>> valueRange = pos.getValuesRange();
        // first value
        Assert.assertEquals("1,'3'", getSubString(sqlArray, valueRange.get(0)));
        // 3nd value
        Assert.assertEquals("3,';,'", getSubString(sqlArray, valueRange.get(2)));
        // 3nd value ,2th col
        Pair<Integer, Integer> valueItemRange = pos.getValueItemsRange().get(2).get(1);
        Assert.assertEquals("';,'", getSubString(sqlArray, valueItemRange));

        Assert.assertEquals(";,", getValueString(sqlArray, valueItemRange));

        Pair<Integer, Integer> valueItemRange1 = pos.getValueItemsRange().get(2).get(0);
        Assert.assertEquals("3", getValueString(sqlArray, valueItemRange1));
    }


    private InsertQueryPos getInsertQueryPos(String sql) {
        InsertParser obj = new InsertParser(sql);
        return obj.parseStatement();
    }

    private String getSubString(char[] src, Pair<Integer, Integer> range) {
        StringBuilder target = new StringBuilder();
        addSubString(src, range, target);
        return target.toString();
    }


    //utils

    private char[] genCatChars(char[] lastChar, char[] nextChar, int lastEndPos, int nextStartPos) {
        char[] sqlChars = new char[lastChar.length - lastEndPos + nextStartPos];
        System.arraycopy(lastChar, lastEndPos, sqlChars, 0, lastChar.length - lastEndPos);
        System.arraycopy(nextChar, 0, sqlChars, lastChar.length - lastEndPos, nextStartPos);
        return sqlChars;
    }

    private String getValueString(char[] src, Pair<Integer, Integer> range) {
        StringBuilder target = new StringBuilder();
        int start = range.getKey();
        int end = range.getValue();
        if (src[start] == '\'' && src[end - 1] == '\'') {
            start++;
            end--;
        }
        for (int i = start; i < end; i++) {
            target.append(src[i]);
        }
        return target.toString();
    }

    private void addSubString(char[] src, Pair<Integer, Integer> range, StringBuilder target) {
        for (int i = range.getKey(); i < range.getValue(); i++) {
            target.append(src[i]);
        }
    }
}
