package feishu

import (
	"encoding/json"
	"testing"
	"time"

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

// TestParseInstanceDetail_AWSApproval tests parsing an AWS approval instance.
func TestParseInstanceDetail_AWSApproval(t *testing.T) {
	// Create a sample AWS approval response
	formFields := []FormField{
		{
			ID:    "widget1",
			Name:  "申请人邮箱",
			Type:  "input",
			Value: json.RawMessage(`"user@pingcap.com"`),
		},
		{
			ID:    "widget2",
			Name:  "申请人选择申请类型",
			Type:  "radioV2",
			Value: json.RawMessage(`"生产账号申请（SSO）"`),
		},
		{
			ID:    "widget3",
			Name:  "生产账号选择",
			Type:  "radioV2",
			Value: json.RawMessage(`"AWS Prod Account (#557537366020)"`),
		},
		{
			ID:    "widget4",
			Name:  "选择生产 SSO Role",
			Type:  "checkboxV2",
			Value: json.RawMessage(`["viewonly", "oncall"]`),
		},
		{
			ID:    "widget5",
			Name:  "申请时间",
			Type:  "dateInterval",
			Value: json.RawMessage(`{"start": "2024-01-01T00:00:00+08:00", "end": "2024-01-10T00:00:00+08:00"}`),
		},
	}

	formJSON, err := json.Marshal(formFields)
	require.NoError(t, err)

	response := InstanceDetailResponse{
		Code: 0,
		Msg:  "success",
		Data: InstanceDetailData{
			InstanceCode: "test-instance-001",
			Status:       "APPROVED",
			Form:         string(formJSON),
		},
	}

	responseJSON, err := json.Marshal(response)
	require.NoError(t, err)

	parser := NewParser()
	data, err := parser.ParseInstanceDetail(responseJSON)

	require.NoError(t, err)
	assert.Equal(t, "user@pingcap.com", data.Email)
	assert.True(t, data.AppType)
	assert.Equal(t, "557537366020", data.AccountID)
	assert.Equal(t, []string{"viewonly", "oncall"}, data.PermissionSets)
	assert.True(t, data.IsApproved)
	assert.Equal(t, "AWS", data.CloudType)
	assert.Equal(t, 9, data.DayNum)
}

// TestParseInstanceDetail_GCPApproval tests parsing a GCP approval instance.
func TestParseInstanceDetail_GCPApproval(t *testing.T) {
	formFields := []FormField{
		{
			ID:    "widget1",
			Name:  "applicant email（xxx@pingcap.com）",
			Type:  "input",
			Value: json.RawMessage(`"gcpuser@pingcap.com"`),
		},
		{
			ID:    "widget2",
			Name:  "Applicant selects application type",
			Type:  "radioV2",
			Value: json.RawMessage(`"Production account application（SSO）"`),
		},
		{
			ID:    "widget3",
			Name:  "GCP Account",
			Type:  "radioV2",
			Value: json.RawMessage(`"GCP"`),
		},
		{
			ID:    "widget4",
			Name:  "GCP Project ID",
			Type:  "radioV2",
			Value: json.RawMessage(`"tidbcloud-prod-000"`),
		},
		{
			ID:    "widget5",
			Name:  "Select the GCP production SSO role",
			Type:  "checkboxV2",
			Value: json.RawMessage(`["DBaaS-Prod-ViewOnly-Role", "DBaaS-Prod-Admin-Role"]`),
		},
		{
			ID:    "widget6",
			Name:  "申请时间",
			Type:  "dateInterval",
			Value: json.RawMessage(`{"start": "2024-02-01T00:00:00+08:00", "end": "2024-02-15T00:00:00+08:00"}`),
		},
	}

	formJSON, err := json.Marshal(formFields)
	require.NoError(t, err)

	response := InstanceDetailResponse{
		Code: 0,
		Msg:  "success",
		Data: InstanceDetailData{
			InstanceCode: "test-instance-002",
			Status:       "APPROVED",
			Form:         string(formJSON),
		},
	}

	responseJSON, err := json.Marshal(response)
	require.NoError(t, err)

	parser := NewParser()
	data, err := parser.ParseInstanceDetail(responseJSON)

	require.NoError(t, err)
	assert.Equal(t, "gcpuser@pingcap.com", data.Email)
	assert.True(t, data.AppType)
	assert.Equal(t, "tidbcloud-prod-000", data.AccountID)
	assert.Equal(t, []string{"DBaaS-Prod-ViewOnly-Role", "DBaaS-Prod-Admin-Role"}, data.PermissionSets)
	assert.True(t, data.IsApproved)
	assert.Equal(t, "GCP", data.CloudType)
}

// TestParseInstanceDetail_AzureApproval tests parsing an Azure approval instance.
func TestParseInstanceDetail_AzureApproval(t *testing.T) {
	formFields := []FormField{
		{
			ID:    "widget1",
			Name:  "申请人邮箱",
			Type:  "input",
			Value: json.RawMessage(`"azureuser@pingcap.com"`),
		},
		{
			ID:    "widget2",
			Name:  "申请人选择申请类型",
			Type:  "radioV2",
			Value: json.RawMessage(`"生产账号申请（SSO）"`),
		},
		{
			ID:    "widget3",
			Name:  "Azure Account",
			Type:  "radioV2",
			Value: json.RawMessage(`"Azure"`),
		},
		{
			ID:    "widget4",
			Name:  "Azure Subscription",
			Type:  "radioV2",
			Value: json.RawMessage(`"tidb-dedicated-prod-controlplane"`),
		},
		{
			ID:    "widget5",
			Name:  "Select the Azure production SSO role",
			Type:  "checkboxV2",
			Value: json.RawMessage(`["Contributor"]`),
		},
		{
			ID:    "widget6",
			Name:  "申请时间",
			Type:  "dateInterval",
			Value: json.RawMessage(`{"start": "2024-03-01T00:00:00+08:00", "end": "2024-03-05T00:00:00+08:00"}`),
		},
	}

	formJSON, err := json.Marshal(formFields)
	require.NoError(t, err)

	response := InstanceDetailResponse{
		Code: 0,
		Msg:  "success",
		Data: InstanceDetailData{
			InstanceCode: "test-instance-003",
			Status:       "APPROVED",
			Form:         string(formJSON),
		},
	}

	responseJSON, err := json.Marshal(response)
	require.NoError(t, err)

	parser := NewParser()
	data, err := parser.ParseInstanceDetail(responseJSON)

	require.NoError(t, err)
	assert.Equal(t, "azureuser@pingcap.com", data.Email)
	assert.True(t, data.AppType)
	assert.Equal(t, "tidb-dedicated-prod-controlplane", data.AccountID)
	assert.Equal(t, []string{"Contributor"}, data.PermissionSets)
	assert.True(t, data.IsApproved)
	assert.Equal(t, "Azure", data.CloudType)
}

// TestParseInstanceDetail_AlibabaApproval tests parsing an Alibaba Cloud approval instance.
func TestParseInstanceDetail_AlibabaApproval(t *testing.T) {
	formFields := []FormField{
		{
			ID:    "widget1",
			Name:  "申请人邮箱",
			Type:  "input",
			Value: json.RawMessage(`"alibabauser@pingcap.com"`),
		},
		{
			ID:    "widget2",
			Name:  "申请人选择申请类型",
			Type:  "radioV2",
			Value: json.RawMessage(`"生产账号申请（SSO）"`),
		},
		{
			ID:    "widget3",
			Name:  "Alibaba Account",
			Type:  "radioV2",
			Value: json.RawMessage(`"Alibaba Prod (#5480039859161595)"`),
		},
		{
			ID:    "widget4",
			Name:  "Select the Alibaba production SSO role",
			Type:  "checkboxV2",
			Value: json.RawMessage(`["Admin", "ReadOnly"]`),
		},
		{
			ID:    "widget5",
			Name:  "申请时间",
			Type:  "dateInterval",
			Value: json.RawMessage(`{"start": "2024-04-01T00:00:00+08:00", "end": "2024-04-07T00:00:00+08:00"}`),
		},
	}

	formJSON, err := json.Marshal(formFields)
	require.NoError(t, err)

	response := InstanceDetailResponse{
		Code: 0,
		Msg:  "success",
		Data: InstanceDetailData{
			InstanceCode: "test-instance-004",
			Status:       "APPROVED",
			Form:         string(formJSON),
		},
	}

	responseJSON, err := json.Marshal(response)
	require.NoError(t, err)

	parser := NewParser()
	data, err := parser.ParseInstanceDetail(responseJSON)

	require.NoError(t, err)
	assert.Equal(t, "alibabauser@pingcap.com", data.Email)
	assert.True(t, data.AppType)
	assert.Equal(t, "5480039859161595", data.AccountID)
	assert.Equal(t, []string{"Admin", "ReadOnly"}, data.PermissionSets)
	assert.True(t, data.IsApproved)
	assert.Equal(t, "Alibaba", data.CloudType)
}

// TestParseInstanceDetail_PendingApproval tests parsing a pending approval instance.
func TestParseInstanceDetail_PendingApproval(t *testing.T) {
	formFields := []FormField{
		{
			ID:    "widget1",
			Name:  "申请人邮箱",
			Type:  "input",
			Value: json.RawMessage(`"pending@pingcap.com"`),
		},
		{
			ID:    "widget2",
			Name:  "申请人选择申请类型",
			Type:  "radioV2",
			Value: json.RawMessage(`"生产账号申请（SSO）"`),
		},
		{
			ID:    "widget3",
			Name:  "生产账号选择",
			Type:  "radioV2",
			Value: json.RawMessage(`"AWS Prod (#557537366020)"`),
		},
		{
			ID:    "widget4",
			Name:  "选择生产 SSO Role",
			Type:  "checkboxV2",
			Value: json.RawMessage(`["viewonly"]`),
		},
	}

	formJSON, err := json.Marshal(formFields)
	require.NoError(t, err)

	response := InstanceDetailResponse{
		Code: 0,
		Msg:  "success",
		Data: InstanceDetailData{
			InstanceCode: "test-instance-005",
			Status:       "PENDING",
			Form:         string(formJSON),
		},
	}

	responseJSON, err := json.Marshal(response)
	require.NoError(t, err)

	parser := NewParser()
	data, err := parser.ParseInstanceDetail(responseJSON)

	require.NoError(t, err)
	assert.False(t, data.IsApproved)
	assert.Equal(t, "pending@pingcap.com", data.Email)
}

// TestParseInstanceDetail_ExpiredPermission tests parsing an expired permission.
func TestParseInstanceDetail_ExpiredPermission(t *testing.T) {
	// Use a past date for end time
	pastTime := time.Now().Add(-24 * time.Hour).Format(time.RFC3339)

	formFields := []FormField{
		{
			ID:    "widget1",
			Name:  "申请人邮箱",
			Type:  "input",
			Value: json.RawMessage(`"expired@pingcap.com"`),
		},
		{
			ID:    "widget2",
			Name:  "申请人选择申请类型",
			Type:  "radioV2",
			Value: json.RawMessage(`"生产账号申请（SSO）"`),
		},
		{
			ID:    "widget3",
			Name:  "生产账号选择",
			Type:  "radioV2",
			Value: json.RawMessage(`"AWS Prod (#557537366020)"`),
		},
		{
			ID:    "widget4",
			Name:  "选择生产 SSO Role",
			Type:  "checkboxV2",
			Value: json.RawMessage(`["viewonly"]`),
		},
		{
			ID:    "widget5",
			Name:  "申请时间",
			Type:  "dateInterval",
			Value: json.RawMessage(`{"start": "2023-01-01T00:00:00+08:00", "end": "` + pastTime + `"}`),
		},
	}

	formJSON, err := json.Marshal(formFields)
	require.NoError(t, err)

	response := InstanceDetailResponse{
		Code: 0,
		Msg:  "success",
		Data: InstanceDetailData{
			InstanceCode: "test-instance-006",
			Status:       "APPROVED",
			Form:         string(formJSON),
		},
	}

	responseJSON, err := json.Marshal(response)
	require.NoError(t, err)

	parser := NewParser()
	data, err := parser.ParseInstanceDetail(responseJSON)

	require.NoError(t, err)
	assert.True(t, data.IsExpired)
	assert.True(t, data.IsApproved)
}

// TestParseInstanceDetail_APIError tests handling API error response.
func TestParseInstanceDetail_APIError(t *testing.T) {
	response := InstanceDetailResponse{
		Code: 99991,
		Msg:  "invalid instance code",
		Data: InstanceDetailData{},
	}

	responseJSON, err := json.Marshal(response)
	require.NoError(t, err)

	parser := NewParser()
	_, err = parser.ParseInstanceDetail(responseJSON)

	assert.Error(t, err)
	assert.Contains(t, err.Error(), "API error")
}

// TestParseInstanceDetail_InvalidJSON tests handling invalid JSON.
func TestParseInstanceDetail_InvalidJSON(t *testing.T) {
	parser := NewParser()
	_, err := parser.ParseInstanceDetail([]byte("invalid json"))

	assert.Error(t, err)
	assert.Contains(t, err.Error(), "failed to unmarshal")
}

// TestParseInstanceDetail_InvalidFormJSON tests handling invalid form JSON.
func TestParseInstanceDetail_InvalidFormJSON(t *testing.T) {
	response := InstanceDetailResponse{
		Code: 0,
		Msg:  "success",
		Data: InstanceDetailData{
			InstanceCode: "test-instance",
			Status:       "APPROVED",
			Form:         "invalid form json",
		},
	}

	responseJSON, err := json.Marshal(response)
	require.NoError(t, err)

	parser := NewParser()
	_, err = parser.ParseInstanceDetail(responseJSON)

	assert.Error(t, err)
	assert.Contains(t, err.Error(), "failed to unmarshal form fields")
}

// TestApprovalData_IsValidApprovalData tests the IsValidApprovalData method.
func TestApprovalData_IsValidApprovalData(t *testing.T) {
	tests := []struct {
		name     string
		data     ApprovalData
		expected bool
	}{
		{
			name: "valid data",
			data: ApprovalData{
				Email:          "user@pingcap.com",
				AppType:        true,
				AccountID:      "557537366020",
				PermissionSets: []string{"viewonly"},
			},
			expected: true,
		},
		{
			name: "missing email",
			data: ApprovalData{
				Email:          "",
				AppType:        true,
				AccountID:      "557537366020",
				PermissionSets: []string{"viewonly"},
			},
			expected: false,
		},
		{
			name: "wrong app type",
			data: ApprovalData{
				Email:          "user@pingcap.com",
				AppType:        false,
				AccountID:      "557537366020",
				PermissionSets: []string{"viewonly"},
			},
			expected: false,
		},
		{
			name: "missing account ID",
			data: ApprovalData{
				Email:          "user@pingcap.com",
				AppType:        true,
				AccountID:      "",
				PermissionSets: []string{"viewonly"},
			},
			expected: false,
		},
		{
			name: "empty permission sets",
			data: ApprovalData{
				Email:          "user@pingcap.com",
				AppType:        true,
				AccountID:      "557537366020",
				PermissionSets: []string{},
			},
			expected: false,
		},
		{
			name: "empty permission string",
			data: ApprovalData{
				Email:          "user@pingcap.com",
				AppType:        true,
				AccountID:      "557537366020",
				PermissionSets: []string{""},
			},
			expected: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := tt.data.IsValidApprovalData()
			assert.Equal(t, tt.expected, result)
		})
	}
}

// TestApprovalData_IsQualifiedForProcessing tests the IsQualifiedForProcessing method.
func TestApprovalData_IsQualifiedForProcessing(t *testing.T) {
	tests := []struct {
		name     string
		data     ApprovalData
		expected bool
	}{
		{
			name: "qualified",
			data: ApprovalData{
				Email:          "user@pingcap.com",
				AppType:        true,
				AccountID:      "557537366020",
				PermissionSets: []string{"viewonly"},
				IsApproved:     true,
				IsExpired:      false,
			},
			expected: true,
		},
		{
			name: "not approved",
			data: ApprovalData{
				Email:          "user@pingcap.com",
				AppType:        true,
				AccountID:      "557537366020",
				PermissionSets: []string{"viewonly"},
				IsApproved:     false,
				IsExpired:      false,
			},
			expected: false,
		},
		{
			name: "expired",
			data: ApprovalData{
				Email:          "user@pingcap.com",
				AppType:        true,
				AccountID:      "557537366020",
				PermissionSets: []string{"viewonly"},
				IsApproved:     true,
				IsExpired:      true,
			},
			expected: false,
		},
		{
			name: "invalid data",
			data: ApprovalData{
				Email:          "",
				AppType:        true,
				AccountID:      "557537366020",
				PermissionSets: []string{"viewonly"},
				IsApproved:     true,
				IsExpired:      false,
			},
			expected: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := tt.data.IsQualifiedForProcessing()
			assert.Equal(t, tt.expected, result)
		})
	}
}

// TestApprovalData_String tests the String method.
func TestApprovalData_String(t *testing.T) {
	data := ApprovalData{
		Email:          "user@pingcap.com",
		CloudType:      "AWS",
		AccountID:      "557537366020",
		PermissionSets: []string{"viewonly", "oncall"},
		IsApproved:     true,
		IsExpired:      false,
	}

	str := data.String()
	assert.Contains(t, str, "user@pingcap.com")
	assert.Contains(t, str, "AWS")
	assert.Contains(t, str, "557537366020")
	assert.Contains(t, str, "viewonly")
	assert.Contains(t, str, "oncall")
}

// TestExtractAccountID tests the extractAccountID helper function.
func TestExtractAccountID(t *testing.T) {
	parser := NewParser()

	tests := []struct {
		name      string
		value     string
		cloudType string
		expected  string
	}{
		{
			name:      "AWS with parentheses",
			value:     "AWS Prod Account (#557537366020)",
			cloudType: "AWS",
			expected:  "557537366020",
		},
		{
			name:      "GCP project ID",
			value:     "tidbcloud-prod-000",
			cloudType: "GCP",
			expected:  "tidbcloud-prod-000",
		},
		{
			name:      "GCP with parentheses",
			value:     "GCP Project (#tidbcloud-prod-000)",
			cloudType: "GCP",
			expected:  "tidbcloud-prod-000",
		},
		{
			name:      "Azure subscription name",
			value:     "tidb-dedicated-prod-controlplane",
			cloudType: "Azure",
			expected:  "tidb-dedicated-prod-controlplane",
		},
		{
			name:      "Alibaba with hash",
			value:     "Alibaba Prod (#5480039859161595)",
			cloudType: "Alibaba",
			expected:  "5480039859161595",
		},
		{
			name:      "plain value",
			value:     "123456789",
			cloudType: "AWS",
			expected:  "123456789",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := parser.extractAccountID(tt.value, tt.cloudType)
			assert.Equal(t, tt.expected, result)
		})
	}
}

// TestDetectCloudType tests the detectCloudType helper function.
func TestDetectCloudType(t *testing.T) {
	parser := NewParser()

	tests := []struct {
		name     string
		fields   []FormField
		expected string
	}{
		{
			name: "GCP detected",
			fields: []FormField{
				{Name: "GCP Account", Type: "radioV2"},
			},
			expected: "GCP",
		},
		{
			name: "Azure detected",
			fields: []FormField{
				{Name: "Azure Subscription", Type: "radioV2"},
			},
			expected: "Azure",
		},
		{
			name: "Alibaba detected",
			fields: []FormField{
				{Name: "Alibaba Account", Type: "radioV2"},
			},
			expected: "Alibaba",
		},
		{
			name: "AWS default",
			fields: []FormField{
				{Name: "生产账号选择", Type: "radioV2"},
			},
			expected: "AWS",
		},
		{
			name:     "empty fields default to AWS",
			fields:   []FormField{},
			expected: "AWS",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := parser.detectCloudType(tt.fields)
			assert.Equal(t, tt.expected, result)
		})
	}
}

// TestParseTime tests the parseTime helper function.
func TestParseTime(t *testing.T) {
	parser := NewParser()

	tests := []struct {
		name      string
		timeStr   string
		expectErr bool
	}{
		{
			name:      "RFC3339 format",
			timeStr:   "2024-01-01T00:00:00+08:00",
			expectErr: false,
		},
		{
			name:      "RFC3339 with Z",
			timeStr:   "2024-01-01T00:00:00Z",
			expectErr: false,
		},
		{
			name:      "date only",
			timeStr:   "2024-01-01",
			expectErr: false,
		},
		{
			name:      "datetime without timezone",
			timeStr:   "2024-01-01 00:00:00",
			expectErr: false,
		},
		{
			name:      "invalid format",
			timeStr:   "invalid",
			expectErr: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			_, err := parser.parseTime(tt.timeStr)
			if tt.expectErr {
				assert.Error(t, err)
			} else {
				assert.NoError(t, err)
			}
		})
	}
}

// TestParseInstanceDetail_SinglePermission tests parsing a single permission (not array).
func TestParseInstanceDetail_SinglePermission(t *testing.T) {
	formFields := []FormField{
		{
			ID:    "widget1",
			Name:  "申请人邮箱",
			Type:  "input",
			Value: json.RawMessage(`"user@pingcap.com"`),
		},
		{
			ID:    "widget2",
			Name:  "申请人选择申请类型",
			Type:  "radioV2",
			Value: json.RawMessage(`"生产账号申请（SSO）"`),
		},
		{
			ID:    "widget3",
			Name:  "生产账号选择",
			Type:  "radioV2",
			Value: json.RawMessage(`"AWS Prod (#557537366020)"`),
		},
		{
			ID:    "widget4",
			Name:  "选择生产 SSO Role",
			Type:  "radioV2", // Single selection, not checkbox
			Value: json.RawMessage(`"viewonly"`),
		},
	}

	formJSON, err := json.Marshal(formFields)
	require.NoError(t, err)

	response := InstanceDetailResponse{
		Code: 0,
		Msg:  "success",
		Data: InstanceDetailData{
			InstanceCode: "test-instance",
			Status:       "APPROVED",
			Form:         string(formJSON),
		},
	}

	responseJSON, err := json.Marshal(response)
	require.NoError(t, err)

	parser := NewParser()
	data, err := parser.ParseInstanceDetail(responseJSON)

	require.NoError(t, err)
	assert.Equal(t, []string{"viewonly"}, data.PermissionSets)
}

// TestParseInstanceDetail_EnglishFieldNames tests parsing with English field names.
func TestParseInstanceDetail_EnglishFieldNames(t *testing.T) {
	formFields := []FormField{
		{
			ID:    "widget1",
			Name:  "applicant email（xxx@pingcap.com）",
			Type:  "input",
			Value: json.RawMessage(`"english@pingcap.com"`),
		},
		{
			ID:    "widget2",
			Name:  "Applicant selects application type",
			Type:  "radioV2",
			Value: json.RawMessage(`"Production account application（SSO）"`),
		},
		{
			ID:    "widget3",
			Name:  "Production account selection",
			Type:  "radioV2",
			Value: json.RawMessage(`"AWS Prod (#380838443567)"`),
		},
		{
			ID:    "widget4",
			Name:  "Select the production SSO role",
			Type:  "checkboxV2",
			Value: json.RawMessage(`["billing", "security"]`),
		},
	}

	formJSON, err := json.Marshal(formFields)
	require.NoError(t, err)

	response := InstanceDetailResponse{
		Code: 0,
		Msg:  "success",
		Data: InstanceDetailData{
			InstanceCode: "test-instance",
			Status:       "APPROVED",
			Form:         string(formJSON),
		},
	}

	responseJSON, err := json.Marshal(response)
	require.NoError(t, err)

	parser := NewParser()
	data, err := parser.ParseInstanceDetail(responseJSON)

	require.NoError(t, err)
	assert.Equal(t, "english@pingcap.com", data.Email)
	assert.True(t, data.AppType)
	assert.Equal(t, "380838443567", data.AccountID)
	assert.Equal(t, []string{"billing", "security"}, data.PermissionSets)
}
