package render

import (
	"testing"
	"text/template"

	"github.com/andygrunwald/go-jira"
	"github.com/golang/mock/gomock"
	"github.com/tidbcloud/jiraport/pkg/clients/clinic"
	"github.com/tidbcloud/jiraport/pkg/clients/engineer"
	"github.com/tidbcloud/jiraport/pkg/entity"
	"github.com/trivago/tgo/tcontainer"
)

func TestRender(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	tmplStr := `
{{ define "issue_url" -}}
[{{ .Key }}]({{ reReplaceAll "rest/api/2/issue/\\d*" "browse" .URL }}/{{ .Key}})
{{- end }}

{{ define "alert_body" -}}
detail {{ template "issue_url" .Issue }}
{{- end }}

{{ define "alert.text" -}}
{{ template "alert_body" . }}
{{- end }}

{{ define "alert.title" -}}
Alert
{{- end }}

{{ define "alert.color" -}}
{{ if reMatch "^(TCA|O11Y)-\\d+$" .Issue.Key }}red{{ else }}yellow{{ end }}
{{- end }}
	`

	clinicClient := clinic.NewMockInterface(ctrl)
	engineerClient := engineer.NewMockInterface(ctrl)
	tmpl, err := template.New("").Funcs(tmplFuncs(clinicClient, engineerClient)).Parse(tmplStr)
	if err != nil {
		t.Error(err)
	}
	render := Render{
		tmpl: tmpl,
	}
	data := map[string]interface{}{
		"Issue": entity.Issue{
			Key: "O11YDEV-123",
			URL: "https://jira.tidbcloud.com/browse/O11YDEV-123",
		},
	}
	title, text, color, err := render.Render("alert", data)
	if err != nil {
		t.Error(err)
	}
	t.Logf("title: %s, text: %s, color: %s", title, text, color)
}

func TestRender2(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	tmplStr := `
	{{ define "alert_body" -}}

	{{ $messages := (stringSlice) -}}

	{{ with .Issue.Description -}}
		{{ with $submatchAll := ( reAllSubmatch "Annotations:\n(?: - .* = .*\n)* - message = (.*)\n" .) -}}
			{{ range $submatchAll -}}
				{{ $messages = (appendString $messages (index . 1)) -}}
			{{ end -}}
			{{ $messages = (unique $messages) -}}
		{{ end -}}
	{{ end -}}

	{{ $runbook := (stringSlice) -}}

	{{ with .Issue.Description -}}
		{{ with $submatchAll := ( reAllSubmatch "Annotations:\n(?: - .* = .*\n)* - runbook_url = (.*)\n" .) -}}
			{{ range $submatchAll -}}
				{{ $runbook = (appendString $runbook (index . 1)) -}}
			{{ end -}}
			{{ $runbook = (unique $runbook) -}}
		{{ end -}}
	{{ end -}}

	**{{ .Issue.Summary }}**

	**Create Time**: {{ .Issue.CreateTime.Format .DefaultTimeFormat }}
	**Priority**: {{ .Issue.Priority }}
	**Component**: {{ .Issue.Component }}
	{{- with .Issue.RawIssue.Fields.Unknowns.customfield_10157 }}
	{{- with $alias := (getAliasByTenant .) }}
	{{- if ne $alias ""}}
	**Tenant**: {{ $alias }}
	{{- end }}
	{{- end }}
	{{- else }}
	{{- with .Issue.RawIssue.Fields.Unknowns.customfield_10149 }}
	{{- with $alias := (getAliasByCluster .) }}
	{{- if ne $alias ""}}
	**Tenant**: {{ $alias }}
	{{- end }}
	{{- end }}
	{{- end }}
	{{- end }}
	{{- with .Issue.RawIssue.Fields.Unknowns.customfield_10149 }}
	{{- with $cname := (getNameByCluster .) }}
	{{- if ne $cname ""}}
	**Cluster Name**: {{ $cname }}
	{{- end }}
	{{- end }}
	{{- end }}
	{{- if .Issue.AssigneeEmail }}
	**Assignee**: {{ .Issue.AssigneeEmail }}
	{{- end }}
	{{- with $messages }}
	**Messages**:{{ range . }}
	 - {{ . }}{{ end }}
	{{- end }}
	{{- with $runbook }}
	**Runbook**:{{ range . }}
	[Runbook Link]({{ . }}{{ end }})
	{{- end }}
	{{- with .Issue.RawIssue.Fields.Unknowns.customfield_10160 }}
	  {{- $parsed := (tryUnmarshalJson .) }}
	  {{- with $parsed }}
		{{- with .labels }}
		  **o11y_region**: {{- .o11y_region }}
		{{- end }}
	  {{- end }}
	{{- end }}
	{{- with .Issue.RawIssue.Fields.Unknowns.customfield_10160 }}
	  {{- $parsed := (tryUnmarshalJson .) }}
	  {{- with $parsed }}
		{{- with .labels }}
		  **o11y_project_id**: {{- .o11y_project_id }}
		{{- end }}
	  {{- end }}
	{{- end }}

	{{- end }}

	{{ define "alert.text" -}}
	{{ template "alert_body" . }}
	{{- end }}

	{{ define "alert.title" -}}
	Alert
	{{- end }}

	{{ define "alert.color" -}}
	{{ if reMatch "^(TCA|O11Y)-\\d+$" .Issue.Key }}red{{ else }}yellow{{ end }}
	{{- end }}
	`

	clinicClient := clinic.NewMockInterface(ctrl)
	engineerClient := engineer.NewMockInterface(ctrl)
	tmpl, err := template.New("").Funcs(tmplFuncs(clinicClient, engineerClient)).Parse(tmplStr)
	if err != nil {
		t.Error(err)
	}
	render := Render{
		tmpl: tmpl,
	}
	customFiled := tcontainer.NewMarshalMap()
	customFiled["customfield_10160"] = `{"status":"firing","labels":{"alertgroup":"manager/manager.rules","alertname":"ManagerIsDown","cluster":"freetier/eks/prod-us-west-2-f02","component":"manager","control_plane_info":"us-west-2-f02/aws-us-west-2","endpoint":"metric","instance":"10.0.135.185:8080","job":"manager","namespace":"tidb-admin","o11y_biz_type":"prod-devtier","o11y_cluster_info":"us-west-2-f02/aws/us-west-2/00c204d6-df82-403a-bdf5-e54a98848094","o11y_id":"00c204d6-df82-403a-bdf5-e54a98848094","o11y_project_id":"us-west-2-f02","o11y_region":"us-west-2","o11y_tenant_id":"prod-devtier","pod":"manager-6b4f69b48d-d7pbx","prometheus":"monitoring-serverless/o11y-service-monitor-vmagent","provider_type":"aws-free-tier","region":"us-west-2","service":"manager","severity":"critical","tier":"serverless"},"annotations":{"message":"region us-west-2, manager of serverless is down.\n"},"startsAt":"2025-02-27T03:48:00Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://vmalert-00c204d6-df82-403a-bdf5-e54a98848094-76c57f5865-mnntw:8080/vmalert/alert?group_id=22700420269479369\u0026alert_id=11007128815288919585"}`
	fields := jira.IssueFields{
		Unknowns: customFiled,
	}
	data := map[string]interface{}{
		"Issue": entity.Issue{
			Key:      "O11YDEV-123",
			URL:      "https://jira.tidbcloud.com/browse/O11YDEV-123",
			RawIssue: entity.RawIssue{Fields: &fields},
		},
	}
	title, text, color, err := render.Render("alert", data)
	if err != nil {
		t.Error(err)
	}
	t.Logf("title: %s, text: %s, color: %s", title, text, color)
}

func TestIsValidClusterID(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	clinicClient := clinic.NewMockInterface(ctrl)
	engineerClient := engineer.NewMockInterface(ctrl)
	funcs := tmplFuncs(clinicClient, engineerClient)
	validFunc := funcs["isValidClusterID"].(func(interface{}) bool)

	tests := []struct {
		name     string
		input    interface{}
		expected bool
	}{
		{
			name:     "numeric cluster ID",
			input:    "1445428518469785",
			expected: true,
		},
		{
			name:     "UUID format cluster ID",
			input:    "dp-6c46820c-1a9a-44f1-8d51-1c24ac261287",
			expected: false,
		},
		{
			name:     "invalid format with letters",
			input:    "tidb1445428518469785",
			expected: false,
		},
		{
			name:     "empty string",
			input:    "",
			expected: false,
		},
		{
			name:     "non-string input",
			input:    123,
			expected: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := validFunc(tt.input)
			if result != tt.expected {
				t.Errorf("isValidClusterID(%v) = %v, want %v", tt.input, result, tt.expected)
			}
		})
	}
}

func TestExtractClusterIDFromAlertData(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	clinicClient := clinic.NewMockInterface(ctrl)
	engineerClient := engineer.NewMockInterface(ctrl)
	funcs := tmplFuncs(clinicClient, engineerClient)
	extractFunc := funcs["extractClusterIDFromAlertData"].(func(interface{}) string)

	tests := []struct {
		name     string
		input    interface{}
		expected string
	}{
		{
			name:     "valid alert data with namespace",
			input:    `{"status":"firing","labels":{"namespace":"tidb1445428518469785","pod":"db-4b0a6920-tikv-xzwhce"},"annotations":{}}`,
			expected: "1445428518469785",
		},
		{
			name:     "alert data with numeric namespace",
			input:    `{"status":"firing","labels":{"namespace":"1445428518469785"},"annotations":{}}`,
			expected: "1445428518469785",
		},
		{
			name:     "invalid JSON",
			input:    "not a json",
			expected: "",
		},
		{
			name:     "JSON without labels",
			input:    `{"status":"firing"}`,
			expected: "",
		},
		{
			name:     "JSON without namespace",
			input:    `{"status":"firing","labels":{"pod":"test"}}`,
			expected: "",
		},
		{
			name:     "empty string",
			input:    "",
			expected: "",
		},
		{
			name:     "non-string input",
			input:    123,
			expected: "",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := extractFunc(tt.input)
			if result != tt.expected {
				t.Errorf("extractClusterIDFromAlertData(%v) = %s, want %s", tt.input, result, tt.expected)
			}
		})
	}
}
