package processor

import (
	"encoding/csv"
	"fmt"
	"os"
	"testing"

	"github.com/golang/mock/gomock"
	"github.com/stretchr/testify/assert"
	mock_data_processor "github.com/tidbcloud/observability/data-collector/test/mockdataprocessor"
)

func Test_getResultType(t *testing.T) {
	result := "{\"fields\": [{\"name\": \"repo_name\"}, {\"name\": \"stars\"}], \"rows\": [{\"repo_name\": \"freeCodeCamp/freeCodeCamp\", \"stars\": 433978}, {\"repo_name\": \"996icu/996.ICU\", \"stars\": 376826}, {\"repo_name\": \"EbookFoundation/free-programming-books\", \"stars\": 290471}, {\"repo_name\": \"jwasham/coding-interview-university\", \"stars\": 269339}, {\"repo_name\": \"sindresorhus/awesome\", \"stars\": 260528}, {\"repo_name\": \"kamranahmedse/developer-roadmap\", \"stars\": 245389}, {\"repo_name\": \"vuejs/vue\", \"stars\": 242674}, {\"repo_name\": \"facebook/react\", \"stars\": 240892}, {\"repo_name\": \"public-apis/public-apis\", \"stars\": 237522}, {\"repo_name\": \"donnemartin/system-design-primer\", \"stars\": 218385}]}"
	tp := getResultType(result)
	assert.Equal(t, "normal", string(tp))
	result = ""
	tp = getResultType(result)
	assert.Equal(t, "empty", string(tp))
	result = "null"
	tp = getResultType(result)
	assert.Equal(t, "null", string(tp))
	result = "{\"fields\": [{\"name\": \"t_month\"}, {\"name\": \"stars\"}], \"rows\": []}"
	tp = getResultType(result)
	assert.Equal(t, "result_empty", string(tp))
}

func TestDataProcessor_JoinCleanedData(t *testing.T) {
	ctl := gomock.NewController(t)
	s3 := mock_data_processor.NewMocks3Client(ctl)
	mockS3 := newMockS3Client(s3)
	processor := newMockDataProcessor(mockS3)
	t.Run("normal", func(t *testing.T) {
		prepareData("./test", "ossinsight", "v1", "test_explorer_questions.csv", [][]string{
			{"id", "title", "status", "user_id", "query_sql", "result", "created_at"},
			{"f5b3171a4f547b2b0aee9c327b92b3f", "bạn là ai", "error", "1170032", "null", "", "2023-03-07 12:21:42"},
			{"iddddd", "test", "error", "1", "null", "null", "2023-03-07 17:29:42"},
		})
		prepareData("./test", "ossinsight", "v1", "test_explorer_question_feedbacks.csv", [][]string{
			{"question_id", "user_id", "feedback_content", "feedback_type", "created_at"},
			{"f5b3171a4f547b2b0aee9c327b92b3f", "0", "cccccc", "error-sql-can-not-answer", "2023-03-07 12:21:52"},
		})
		defer deleteData("./test")
		err := processor.JoinCleanedData("test", "test", "ossinsight", "v1")
		assert.NoError(t, err)
		file, _ := os.Open("./test/ossinsight/v1/20230307.csv")
		reader := csv.NewReader(file)
		head, _ := reader.Read()
		assert.Equal(t, "question_id", head[0])
		row, _ := reader.Read()
		assert.NotEmpty(t, row[6])
	})
	t.Run("other", func(t *testing.T) {
		prepareData("./test", "ossinsight", "v1", "test_explorer_questions.csv", [][]string{
			{"id", "title", "status", "user_id", "query_sql", "result", "created_at"},
			{"f5b3171a4f547b2b0aee9c327b92b3f", "bạn là ai", "error", "1170032", "null", "", "2023-03-07 12:21:42"},
			{"iddddd", "test", "error", "1", "null", "null", "2023-03-07 17:29:42"},
		})
		prepareData("./test", "ossinsight", "v1", "test_explorer_question_feedbacks.csv", [][]string{
			{"question_id", "user_id", "feedback_content", "feedback_type", "created_at"},
			{"f5b3171a4f547b2b0aee9c327b92b3f", "0", "cccccc", "error-sql-can-not-answer", "2023-03-07 12:21:52"},
		})
		defer deleteData("./test")
		err := processor.JoinCleanedData("test", "test", "other", "v1")
		assert.NoError(t, err)
	})

	t.Run("write error", func(t *testing.T) {
		prepareData("./test", "ossinsight", "v1", "test_explorer_questions.csv", [][]string{
			{"id", "title", "status", "user_id", "query_sql", "result", "created_at"},
			{"f5b3171a4f547b2b0aee9c327b92b3f", "bạn là ai", "error", "1170032", "null", "", "2023-03-07 12:21:42"},
			{"iddddd", "test", "error", "1", "null", "null", "2023-03-07 17:29:42"},
		})
		prepareData("./test", "ossinsight", "v1", "test_explorer_question_feedbacks.csv", [][]string{
			{"question_id", "user_id", "feedback_content", "feedback_type", "created_at"},
			{"f5b3171a4f547b2b0aee9c327b92b3f", "0", "cccccc", "error-sql-can-not-answer", "2023-03-07 12:21:52"},
		})
		defer deleteData("./test")
		WriteCsvFileFunc = func(writer *csv.Writer, content []string) error {
			return fmt.Errorf("error")
		}
		defer func() {
			WriteCsvFileFunc = func(writer *csv.Writer, content []string) error {
				return WriteCsvFile(writer, content)
			}
		}()
		err := processor.JoinCleanedData("test", "test", "ossinsight", "v1")
		assert.Error(t, err)
	})

	t.Run("read error", func(t *testing.T) {
		prepareData("./test", "ossinsight", "v1", "test_explorer_questions.csv", [][]string{
			{"id", "title", "status", "user_id", "query_sql", "result", "created_at"},
			{"f5b3171a4f547b2b0aee9c327b92b3f", "bạn là ai", "error", "1170032", "null", "", "2023-03-07 12:21:42"},
			{"iddddd", "test", "error", "1", "null", "null", "2023-03-07 17:29:42"},
		})
		prepareData("./test", "ossinsight", "v1", "test_explorer_question_feedbacks.csv", [][]string{
			{"question_id", "user_id", "feedback_content", "feedback_type", "created_at"},
			{"f5b3171a4f547b2b0aee9c327b92b3f", "0", "cccccc", "error-sql-can-not-answer", "2023-03-07 12:21:52"},
		})
		defer deleteData("./test")
		readFileToMapV2Func = func(path string, mp map[string]map[string]string, selectedID string) error {
			return fmt.Errorf("error")
		}
		defer func() {
			readFileToMapV2Func = func(path string, mp map[string]map[string]string, selectedID string) error {
				return readFileToMapV2(path, mp, selectedID)
			}
		}()
		err := processor.JoinCleanedData("test", "test", "ossinsight", "v1")
		assert.Error(t, err)
	})

	t.Run("delete error", func(t *testing.T) {
		DeleteFilesFunc = func(pattern string) error {
			return fmt.Errorf("error")
		}
		defer func() {
			DeleteFilesFunc = func(pattern string) error {
				return DeleteFiles(pattern)
			}
		}()
		err := processor.JoinCleanedData("test", "test", "ossinsight", "v1")
		assert.NoError(t, err)
	})
}
