package parser

import (
	"testing"
	"time"

	"code.justin.tv/creator-collab/log"
	"github.com/aws/aws-lambda-go/events"

	"github.com/stretchr/testify/require"
)

func TestParseCloudWatchLogsInsightsTime(t *testing.T) {
	parsedTime, err := parseCloudWatchLogsInsightsTime("2020-09-17 17:22:53.564")
	require.NoError(t, err)
	require.Equal(t, parsedTime, time.Date(2020, 9, 17, 17, 22, 53, 564*1000000, time.UTC))
}

func TestParseUnixMilliseconds(t *testing.T) {
	parsedTime := parseUnixMilliseconds(1600483471973)
	require.Equal(t, parsedTime, time.Date(2020, 9, 19, 2, 44, 31, 973*1000000, time.UTC))
}

func Test_Parser_Parse_StreamScheduleEvent(t *testing.T) {
	msg := "{" +
		"\"fingerprint\":\"6d23074e\"," +
		"\"msg\":\"segments_reporter.DeleteAll: no segments found\"," +
		"\"rid\":\"01EJMEKY538RD6R13TPKXZRM4Z\"," +
		"\"scheduleID\":\"schedule-43375280\"," +
		"\"state\":\"error\"," +
		"\"traces.0.filename\":\"/local/p4clients/pkgbuild-8JP8M/workspace/src/StreamSchedule/storage/segments.go\"," +
		"\"traces.0.line\":\"22\"," +
		"\"traces.0.method\":\"init\"," +
		"\"traces.1.filename\":\"/opt/brazil-pkg-cache/packages/GoLang/GoLang-1.x.6797.0/AL2_x86_64/DEV.STD.PTHREAD/build/lib/src/runtime/proc.go\"," +
		"\"traces.1.line\":\"5420\"," +
		"\"traces.1.method\":\"doInit\"," +
		"\"traces.2.filename\":\"/opt/brazil-pkg-cache/packages/GoLang/GoLang-1.x.6797.0/AL2_x86_64/DEV.STD.PTHREAD/build/lib/src/runtime/proc.go\"," +
		"\"traces.2.line\":\"5415\"," +
		"\"traces.2.method\":\"doInit\"," +
		"\"traces.3.filename\":\"/opt/brazil-pkg-cache/packages/GoLang/GoLang-1.x.6797.0/AL2_x86_64/DEV.STD.PTHREAD/build/lib/src/runtime/proc.go\"," +
		"\"traces.3.line\":\"5415\"," +
		"\"traces.3.method\":\"doInit\"," +
		"\"traces.4.filename\":\"/opt/brazil-pkg-cache/packages/GoLang/GoLang-1.x.6797.0/AL2_x86_64/DEV.STD.PTHREAD/build/lib/src/runtime/proc.go\"," +
		"\"traces.4.line\":\"5415\"," +
		"\"traces.4.method\":\"doInit\"," +
		"\"traces.5.filename\":\"/opt/brazil-pkg-cache/packages/GoLang/GoLang-1.x.6797.0/AL2_x86_64/DEV.STD.PTHREAD/build/lib/src/runtime/proc.go\"," +
		"\"traces.5.line\":\"190\"," +
		"\"traces.5.method\":\"main\"," +
		"\"traces.6.filename\":\"/opt/brazil-pkg-cache/packages/GoLang/GoLang-1.x.6797.0/AL2_x86_64/DEV.STD.PTHREAD/build/lib/src/runtime/asm_amd64.s\"," +
		"\"traces.6.line\":\"1373\"," +
		"\"traces.6.method\":\"goexit\"," +
		"\"twirp.method\":\"DeleteSchedule\"," +
		"\"twirp.package\":\"twitch.fulton.example.streamschedule\"," +
		"\"twirp.service\":\"StreamSchedule\"" +
		"}"
	cwlData := &events.CloudwatchLogsData{
		Owner:     "1111111111",
		LogGroup:  "/aws/ecs/StreamSchedule-prod",
		LogStream: "StreamSchedule-prod/StreamSchedule/37b7f04e-df14-4000-b808-5ce2c5aa261b",
		SubscriptionFilters: []string{
			"CdkStack-TestSubscription7561CFEF-1PSKOXFNAX3WF",
		},
		MessageType: "DATA_MESSAGE",
		LogEvents: []events.CloudwatchLogsLogEvent{
			{
				ID:        "35691974102929500905463172772288161745722736368435920897",
				Timestamp: 1600483471973,
				Message:   msg,
			},
		},
	}

	parser := Parser{
		logger: log.NewDevelopmentLogger(),
	}
	logEvents, err := parser.Parse(cwlData)
	require.NoError(t, err)
	require.Len(t, logEvents, 1)
	logEvent := logEvents[0]

	require.Equal(t, "segments_reporter.DeleteAll: no segments found", logEvent.Message)
	require.Equal(t, msg, logEvent.Raw)
	require.Equal(t, cwlData.LogEvents[0].ID, logEvent.LogEventID)
	require.Equal(t, time.Date(2020, 9, 19, 2, 44, 31, 973*1000000, time.UTC), logEvent.Timestamp)
	require.Equal(t, cwlData.Owner, logEvent.AccountID)
	require.Equal(t, cwlData.LogGroup, logEvent.LogGroup)
	require.Equal(t, cwlData.LogStream, logEvent.LogStream)
	require.Equal(t, "6d23074e", logEvent.Fingerprint)
	require.Equal(t, "01EJMEKY538RD6R13TPKXZRM4Z", logEvent.RequestID)
	require.Equal(t, "DeleteSchedule", logEvent.Operation)
	require.Equal(t, "error", logEvent.Level)
	require.Empty(t, logEvent.Fields)
	require.Equal(t, []StackTrace{
		{
			FullFilePath:      "/local/p4clients/pkgbuild-8JP8M/workspace/src/StreamSchedule/storage/segments.go",
			Method:            "init",
			Line:              22,
			ShortFilePath:     "storage/segments.go",
			BrazilPackageName: "StreamSchedule",
			Relevant:          true,
			LineURL:           "https://code.amazon.com/packages/StreamSchedule/blobs/mainline/--/storage/segments.go#L22",
			PackageURL:        "https://code.amazon.com/packages/StreamSchedule",
		},
		{
			FullFilePath:      "/opt/brazil-pkg-cache/packages/GoLang/GoLang-1.x.6797.0/AL2_x86_64/DEV.STD.PTHREAD/build/lib/src/runtime/proc.go",
			Method:            "doInit",
			Line:              5420,
			ShortFilePath:     "runtime/proc.go",
			BrazilPackageName: "GoLang",
			Relevant:          false,
			LineURL:           "",
			PackageURL:        "https://code.amazon.com/packages/GoLang",
		},
		{
			FullFilePath:      "/opt/brazil-pkg-cache/packages/GoLang/GoLang-1.x.6797.0/AL2_x86_64/DEV.STD.PTHREAD/build/lib/src/runtime/proc.go",
			Method:            "doInit",
			Line:              5415,
			ShortFilePath:     "runtime/proc.go",
			BrazilPackageName: "GoLang",
			Relevant:          false,
			LineURL:           "",
			PackageURL:        "https://code.amazon.com/packages/GoLang",
		},
		{
			FullFilePath:      "/opt/brazil-pkg-cache/packages/GoLang/GoLang-1.x.6797.0/AL2_x86_64/DEV.STD.PTHREAD/build/lib/src/runtime/proc.go",
			Method:            "doInit",
			Line:              5415,
			ShortFilePath:     "runtime/proc.go",
			BrazilPackageName: "GoLang",
			Relevant:          false,
			LineURL:           "",
			PackageURL:        "https://code.amazon.com/packages/GoLang",
		},
		{
			FullFilePath:      "/opt/brazil-pkg-cache/packages/GoLang/GoLang-1.x.6797.0/AL2_x86_64/DEV.STD.PTHREAD/build/lib/src/runtime/proc.go",
			Method:            "doInit",
			Line:              5415,
			ShortFilePath:     "runtime/proc.go",
			BrazilPackageName: "GoLang",
			Relevant:          false,
			LineURL:           "",
			PackageURL:        "https://code.amazon.com/packages/GoLang",
		},
		{
			FullFilePath:      "/opt/brazil-pkg-cache/packages/GoLang/GoLang-1.x.6797.0/AL2_x86_64/DEV.STD.PTHREAD/build/lib/src/runtime/proc.go",
			Method:            "main",
			Line:              190,
			ShortFilePath:     "runtime/proc.go",
			BrazilPackageName: "GoLang",
			Relevant:          false,
			LineURL:           "",
			PackageURL:        "https://code.amazon.com/packages/GoLang",
		},
		{
			FullFilePath:      "/opt/brazil-pkg-cache/packages/GoLang/GoLang-1.x.6797.0/AL2_x86_64/DEV.STD.PTHREAD/build/lib/src/runtime/asm_amd64.s",
			Method:            "goexit",
			Line:              1373,
			ShortFilePath:     "runtime/asm_amd64.s",
			BrazilPackageName: "GoLang",
			Relevant:          false,
			LineURL:           "",
			PackageURL:        "https://code.amazon.com/packages/GoLang",
		},
	}, logEvent.StackTrace)
}

func Test_Parser_Parse_ShelfieEvent(t *testing.T) {
	msg := "{" +
		`"error": "twirp error internal: backend service error; requestId: 4c122c91-6a8e-4346-8345-7a8290e86286",` +
		`"msg": "GetRecommendedCategories Failure",` +
		`"request_id": "4c122c91-6a8e-4346-8345-7a8290e86286"` +
		"}"

	cwlData := &events.CloudwatchLogsData{
		Owner:     "1111111111",
		LogGroup:  "/aws/ecs/Shelfie-prod-Canary",
		LogStream: "Shelfie-prod-Canary/Shelfie-Canary/5624f0b9-b222-442f-8f9d-ec2e08b92a5a",
		SubscriptionFilters: []string{
			"CdkStack-TestSubscription7561CFEF-1PSKOXFNAX3WF",
		},
		MessageType: "DATA_MESSAGE",
		LogEvents: []events.CloudwatchLogsLogEvent{
			{
				ID:        "35691974102929500905463172772288161745722736368435920897",
				Timestamp: 1600483471973,
				Message:   msg,
			},
		},
	}

	parser := Parser{
		logger: log.NewDevelopmentLogger(),
	}
	logEvents, err := parser.Parse(cwlData)
	require.NoError(t, err)
	require.Len(t, logEvents, 1)
	logEvent := logEvents[0]

	require.Equal(t, "GetRecommendedCategories Failure: twirp error internal: backend service error; requestId: 4c122c91-6a8e-4346-8345-7a8290e86286", logEvent.Message)
	require.Equal(t, msg, logEvent.Raw)
	require.Equal(t, cwlData.LogEvents[0].ID, logEvent.LogEventID)
	require.Equal(t, time.Date(2020, 9, 19, 2, 44, 31, 973*1000000, time.UTC), logEvent.Timestamp)
	require.Equal(t, cwlData.Owner, logEvent.AccountID)
	require.Equal(t, cwlData.LogGroup, logEvent.LogGroup)
	require.Equal(t, cwlData.LogStream, logEvent.LogStream)
	require.Equal(t, "4c122c91-6a8e-4346-8345-7a8290e86286", logEvent.RequestID)
	require.Equal(t, "error", logEvent.Level)

	require.NotEmpty(t, logEvent.Fingerprint)

	require.Empty(t, logEvent.Operation)
	require.Empty(t, logEvent.Fields)
	require.Empty(t, logEvent.StackTrace)
}

func Test_Sanitize_Guid(t *testing.T) {
	s1 := sanitize("twirp error internal: backend service error; requestId: 4c122c91-6a8e-4346-8345-7a8290e86286: context canceled")
	s2 := sanitize("twirp error internal: backend service error; requestId: c6580504-9ec6-4378-be25-e79b10e1576f: context canceled")
	require.Equal(t, s1, s2)
}
