package metrics

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"veza-backend-api/internal/errors"
)

func TestErrorMetrics_RecordError(t *testing.T) {
	metrics := NewErrorMetrics()
	metrics.RecordError(errors.ErrCodeNotFound, 404)
	metrics.RecordError(errors.ErrCodeValidation, 400)

	stats := metrics.GetStats()
	assert.Equal(t, int64(2), stats["total_errors"])

	errorsByCode := stats["errors_by_code"].(map[errors.ErrorCode]int64)
	assert.Equal(t, int64(1), errorsByCode[errors.ErrCodeNotFound])
	assert.Equal(t, int64(1), errorsByCode[errors.ErrCodeValidation])

	errorsByHTTPStatus := stats["errors_by_http_status"].(map[int]int64)
	assert.Equal(t, int64(1), errorsByHTTPStatus[404])
	assert.Equal(t, int64(1), errorsByHTTPStatus[400])
}

func TestErrorMetrics_MultipleSameError(t *testing.T) {
	metrics := NewErrorMetrics()

	// Enregistrer plusieurs fois la même erreur
	for i := 0; i < 5; i++ {
		metrics.RecordError(errors.ErrCodeValidation, 400)
	}

	stats := metrics.GetStats()
	assert.Equal(t, int64(5), stats["total_errors"])

	errorsByCode := stats["errors_by_code"].(map[errors.ErrorCode]int64)
	assert.Equal(t, int64(5), errorsByCode[errors.ErrCodeValidation])

	errorsByHTTPStatus := stats["errors_by_http_status"].(map[int]int64)
	assert.Equal(t, int64(5), errorsByHTTPStatus[400])
}

func TestErrorMetrics_ConcurrentAccess(t *testing.T) {
	metrics := NewErrorMetrics()

	// Simuler des accès concurrents
	done := make(chan bool, 10)
	for i := 0; i < 10; i++ {
		go func(index int) {
			metrics.RecordError(errors.ErrCodeInternal, 500)
			done <- true
		}(i)
	}

	// Attendre que toutes les goroutines terminent
	for i := 0; i < 10; i++ {
		<-done
	}

	stats := metrics.GetStats()
	assert.Equal(t, int64(10), stats["total_errors"])

	errorsByCode := stats["errors_by_code"].(map[errors.ErrorCode]int64)
	assert.Equal(t, int64(10), errorsByCode[errors.ErrCodeInternal])
}

func TestErrorMetrics_GetStats(t *testing.T) {
	metrics := NewErrorMetrics()
	metrics.RecordError(errors.ErrCodeNotFound, 404)
	metrics.RecordError(errors.ErrCodeValidation, 400)
	metrics.RecordError(errors.ErrCodeUnauthorized, 401)

	stats := metrics.GetStats()

	assert.NotNil(t, stats["total_errors"])
	assert.NotNil(t, stats["errors_by_code"])
	assert.NotNil(t, stats["errors_by_http_status"])

	assert.Equal(t, int64(3), stats["total_errors"])

	errorsByCode := stats["errors_by_code"].(map[errors.ErrorCode]int64)
	assert.Equal(t, 3, len(errorsByCode))

	errorsByHTTPStatus := stats["errors_by_http_status"].(map[int]int64)
	assert.Equal(t, 3, len(errorsByHTTPStatus))
}

func TestErrorMetrics_EmptyStats(t *testing.T) {
	metrics := NewErrorMetrics()
	stats := metrics.GetStats()

	assert.Equal(t, int64(0), stats["total_errors"])

	errorsByCode := stats["errors_by_code"].(map[errors.ErrorCode]int64)
	assert.Equal(t, 0, len(errorsByCode))

	errorsByHTTPStatus := stats["errors_by_http_status"].(map[int]int64)
	assert.Equal(t, 0, len(errorsByHTTPStatus))
}

func TestErrorMetrics_Reset(t *testing.T) {
	metrics := NewErrorMetrics()
	metrics.RecordError(errors.ErrCodeNotFound, 404)
	metrics.RecordError(errors.ErrCodeValidation, 400)

	stats := metrics.GetStats()
	assert.Equal(t, int64(2), stats["total_errors"])

	metrics.Reset()

	stats = metrics.GetStats()
	assert.Equal(t, int64(0), stats["total_errors"])

	errorsByCode := stats["errors_by_code"].(map[errors.ErrorCode]int64)
	assert.Equal(t, 0, len(errorsByCode))
}

func TestNewErrorMetrics(t *testing.T) {
	metrics := NewErrorMetrics()
	assert.NotNil(t, metrics)

	stats := metrics.GetStats()
	assert.Equal(t, int64(0), stats["total_errors"])
	assert.NotNil(t, stats["errors_by_code"])
	assert.NotNil(t, stats["errors_by_http_status"])
}

func TestErrorMetrics_DifferentHTTPStatuses(t *testing.T) {
	metrics := NewErrorMetrics()

	// Tester différents codes HTTP
	metrics.RecordError(errors.ErrCodeValidation, 400)
	metrics.RecordError(errors.ErrCodeUnauthorized, 401)
	metrics.RecordError(errors.ErrCodeForbidden, 403)
	metrics.RecordError(errors.ErrCodeNotFound, 404)
	metrics.RecordError(errors.ErrCodeConflict, 409)
	metrics.RecordError(errors.ErrCodeRateLimitExceeded, 429)
	metrics.RecordError(errors.ErrCodeInternal, 500)

	stats := metrics.GetStats()
	assert.Equal(t, int64(7), stats["total_errors"])

	errorsByHTTPStatus := stats["errors_by_http_status"].(map[int]int64)
	assert.Equal(t, int64(1), errorsByHTTPStatus[400])
	assert.Equal(t, int64(1), errorsByHTTPStatus[401])
	assert.Equal(t, int64(1), errorsByHTTPStatus[403])
	assert.Equal(t, int64(1), errorsByHTTPStatus[404])
	assert.Equal(t, int64(1), errorsByHTTPStatus[409])
	assert.Equal(t, int64(1), errorsByHTTPStatus[429])
	assert.Equal(t, int64(1), errorsByHTTPStatus[500])
}
