// File: dbconfig_test.go
package config

import (
	"bytes"
	"os"
	"testing"

	log "github.com/sirupsen/logrus"
	"github.com/stretchr/testify/assert"
	"github.com/tidbcloud/observability/o11ymetering/pkg/common/constants"
)

func TestGetConfigFunctions(t *testing.T) {
	// Ensure meteringConfig is loaded before testing Get functions
	validConfigContent := `
auth0:
  grantType: "client_credentials"
  clientID: "test_client_id"
  clientSecret: "test_client_secret"
  audience: "test_audience"
databases:
  - type: "mysql"
    dsn: "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
    use: "metering"
periodConfig:
  firstPeriod: "2023-01"
tasks:
  - statisticClass: "daily"
    meteringGroup: "cloud"
    env: "production"
categoryShareProportions:
  - cloudService: "tidb"
    category: "compute"
    proportion: 0.5
scheduleConfig:
  generateStatisticTaskIntervalSeconds: 3600
  executeStatisticTaskIntervalSeconds: 600
  mergeStatisticIntervalHours: 24
  mergeStatisticImmediately: false
  generateStatisticReportIntervalHours: 24
  generateStatisticReportImmediately: false
  clearStatisticDataIntervalHours: 720
  monthlyProportion: true
  renewMonthlyProportionTs: 1672531200
`
	err := os.WriteFile("test_valid_config.yaml", []byte(validConfigContent), 0644)
	assert.NoError(t, err)
	defer os.Remove("test_valid_config.yaml")
	LoadMeteringConfig("test_valid_config.yaml")

	// Test GetDatabases
	dbs := GetDatabases()
	assert.NotNil(t, dbs)
	assert.Equal(t, 1, len(dbs))
	assert.Equal(t, "mysql", dbs[0].Type)

	// Test GetAuth0Config
	auth0 := GetAuth0Config()
	assert.NotNil(t, auth0)
	assert.Equal(t, "test_client_id", auth0.ClientID)

	// Test GetPeriodConfig
	period := GetPeriodConfig()
	assert.NotNil(t, period)
	assert.Equal(t, "2023-01", period.FirstPeriod)

	// Test GetTasks
	tasks := GetTasks()
	assert.NotNil(t, tasks)
	assert.Equal(t, 1, len(tasks))
	assert.Equal(t, constants.StatisticClass("daily"), tasks[0].StatisticClass)

	// Test GetScheduleConfig
	schedule := GetScheduleConfig()
	assert.NotNil(t, schedule)
	assert.Equal(t, 3600, schedule.GenerateStatisticTaskIntervalSeconds)

	// Temporarily set meteringConfig to nil to test panic
	originalConfig := meteringConfig
	meteringConfig = nil
	assert.PanicsWithValue(t, "metering config is empty", func() { GetDatabases() })
	assert.PanicsWithValue(t, "metering config is empty", func() { GetAuth0Config() })
	assert.PanicsWithValue(t, "metering config is empty", func() { GetPeriodConfig() })
	assert.PanicsWithValue(t, "metering config is empty", func() { GetTasks() })
	assert.PanicsWithValue(t, "metering config is empty", func() { GetScheduleConfig() })
	meteringConfig = originalConfig // Restore
}

func TestGetCategoryShareProportion(t *testing.T) {
	// Ensure meteringConfig is loaded
	validConfigContent := `
auth0:
  grantType: "client_credentials"
  clientID: "test_client_id"
  clientSecret: "test_client_secret"
  audience: "test_audience"
databases:
  - type: "mysql"
    dsn: "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
    use: "metering"
periodConfig:
  firstPeriod: "2023-01"
tasks:
  - statisticClass: "daily"
    meteringGroup: "cloud"
    env: "production"
categoryShareProportions:
  - cloudService: "tidb"
    category: "compute"
    proportion: 0.5
  - cloudService: "ticdc"
    category: "storage"
    proportion: 0.3
scheduleConfig:
  generateStatisticTaskIntervalSeconds: 3600
  executeStatisticTaskIntervalSeconds: 600
  mergeStatisticIntervalHours: 24
  mergeStatisticImmediately: false
  generateStatisticReportIntervalHours: 24
  generateStatisticReportImmediately: false
  clearStatisticDataIntervalHours: 720
  monthlyProportion: true
  renewMonthlyProportionTs: 1672531200
`
	err := os.WriteFile("test_valid_config.yaml", []byte(validConfigContent), 0644)
	assert.NoError(t, err)
	defer os.Remove("test_valid_config.yaml")
	LoadMeteringConfig("test_valid_config.yaml")

	// Test existing proportion
	proportion := GetCategoryShareProportion(constants.Category("compute"), constants.CloudService("tidb"))
	assert.Equal(t, 0.5, proportion)

	// Test another existing proportion
	proportion = GetCategoryShareProportion(constants.Category("storage"), constants.CloudService("ticdc"))
	assert.Equal(t, 0.3, proportion)

	// Test non-existent proportion (should return 0 and log a warning)
	// Capture log output to verify warning
	var logBuffer bytes.Buffer
	log.SetOutput(&logBuffer)
	defer func() {
		log.SetOutput(os.Stderr) // Restore default output
	}()

	proportion = GetCategoryShareProportion(constants.Category("network"), constants.CloudService("tidb"))
	assert.Equal(t, 0.0, proportion)
	assert.Contains(t, logBuffer.String(), "undifined CategoryShareProportion")

	// Test panic when meteringConfig is empty
	originalConfig := meteringConfig
	meteringConfig = nil
	assert.PanicsWithValue(t, "metering config is empty", func() {
		GetCategoryShareProportion(constants.Category("compute"), constants.CloudService("tidb"))
	})
	meteringConfig = originalConfig // Restore
}
