package handlers

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"net/http/httptest"
	"os"
	"strings"
	"testing"
	"time"

	"github.com/Wikid82/charon/backend/internal/crypto"
	"github.com/Wikid82/charon/backend/internal/models"
	"github.com/Wikid82/charon/backend/internal/services"
	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

// =============================================================================
// Additional Plugin Handler Tests for Coverage
// =============================================================================

func TestPluginHandler_EnablePlugin_DatabaseUpdateError(t *testing.T) {
	gin.SetMode(gin.TestMode)
	db := OpenTestDBWithMigrations(t)
	pluginLoader := services.NewPluginLoaderService(db, "/tmp/plugins", nil)

	// Create plugin
	plugin := models.Plugin{
		UUID:     "plugin-db-error-uuid",
		Name:     "Test Plugin",
		Type:     "test-type",
		Enabled:  false,
		Status:   models.PluginStatusError,
		FilePath: "/nonexistent/path.so",
	}
	db.Create(&plugin)

	handler := NewPluginHandler(db, pluginLoader)

	// Close DB to trigger error during update
	sqlDB, _ := db.DB()
	_ = sqlDB.Close()

	router := gin.New()
	router.POST("/plugins/:id/enable", handler.EnablePlugin)

	req := httptest.NewRequest(http.MethodPost, "/plugins/1/enable", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusInternalServerError, w.Code)
}

func TestPluginHandler_DisablePlugin_DatabaseUpdateError(t *testing.T) {
	gin.SetMode(gin.TestMode)
	db := OpenTestDBWithMigrations(t)
	pluginLoader := services.NewPluginLoaderService(db, "/tmp/plugins", nil)

	// Create plugin
	plugin := models.Plugin{
		UUID:     "plugin-disable-error-uuid",
		Name:     "Test Plugin",
		Type:     "test-type-disable",
		Enabled:  true,
		Status:   models.PluginStatusLoaded,
		FilePath: "/path/to/plugin.so",
	}
	db.Create(&plugin)

	handler := NewPluginHandler(db, pluginLoader)

	// Close DB to trigger error during update
	sqlDB, _ := db.DB()
	_ = sqlDB.Close()

	router := gin.New()
	router.POST("/plugins/:id/disable", handler.DisablePlugin)

	req := httptest.NewRequest(http.MethodPost, "/plugins/1/disable", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusInternalServerError, w.Code)
}

func TestPluginHandler_GetPlugin_DatabaseError(t *testing.T) {
	gin.SetMode(gin.TestMode)
	db := OpenTestDBWithMigrations(t)
	pluginLoader := services.NewPluginLoaderService(db, "/tmp/plugins", nil)

	// Create plugin first
	plugin := models.Plugin{
		UUID:     "get-error-uuid",
		Name:     "Get Error",
		Type:     "get-error-type",
		Enabled:  true,
		FilePath: "/path/to/get.so",
	}
	db.Create(&plugin)

	handler := NewPluginHandler(db, pluginLoader)

	// Close DB to trigger database error
	sqlDB, _ := db.DB()
	_ = sqlDB.Close()

	router := gin.New()
	router.GET("/plugins/:id", handler.GetPlugin)

	req := httptest.NewRequest(http.MethodGet, "/plugins/1", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusInternalServerError, w.Code)
	assert.Contains(t, w.Body.String(), "Failed to get plugin")
}

func TestPluginHandler_EnablePlugin_DatabaseFirstError(t *testing.T) {
	gin.SetMode(gin.TestMode)
	db := OpenTestDBWithMigrations(t)
	pluginLoader := services.NewPluginLoaderService(db, "/tmp/plugins", nil)

	handler := NewPluginHandler(db, pluginLoader)

	// Close DB to trigger error when fetching plugin
	sqlDB, _ := db.DB()
	_ = sqlDB.Close()

	router := gin.New()
	router.POST("/plugins/:id/enable", handler.EnablePlugin)

	req := httptest.NewRequest(http.MethodPost, "/plugins/1/enable", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusInternalServerError, w.Code)
	assert.Contains(t, w.Body.String(), "Failed to get plugin")
}

func TestPluginHandler_DisablePlugin_DatabaseFirstError(t *testing.T) {
	gin.SetMode(gin.TestMode)
	db := OpenTestDBWithMigrations(t)
	pluginLoader := services.NewPluginLoaderService(db, "/tmp/plugins", nil)

	handler := NewPluginHandler(db, pluginLoader)

	// Close DB to trigger error when fetching plugin
	sqlDB, _ := db.DB()
	_ = sqlDB.Close()

	router := gin.New()
	router.POST("/plugins/:id/disable", handler.DisablePlugin)

	req := httptest.NewRequest(http.MethodPost, "/plugins/1/disable", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusInternalServerError, w.Code)
	assert.Contains(t, w.Body.String(), "Failed to get plugin")
}

// =============================================================================
// Encryption Handler - Additional Coverage Tests
// =============================================================================

func TestEncryptionHandler_Validate_NonAdminAccess(t *testing.T) {
	gin.SetMode(gin.TestMode)

	currentKey, _ := crypto.GenerateNewKey()
	os.Setenv("CHARON_ENCRYPTION_KEY", currentKey)
	defer os.Unsetenv("CHARON_ENCRYPTION_KEY")

	db := setupEncryptionTestDB(t)
	rotationService, _ := crypto.NewRotationService(db)
	securityService := services.NewSecurityService(db)
	defer securityService.Close()

	handler := NewEncryptionHandler(rotationService, securityService)
	router := setupEncryptionTestRouter(handler, false)

	w := httptest.NewRecorder()
	req, _ := http.NewRequest("POST", "/api/v1/admin/encryption/validate", nil)
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusForbidden, w.Code)
}

func TestEncryptionHandler_GetHistory_PaginationBoundary(t *testing.T) {
	gin.SetMode(gin.TestMode)

	currentKey, _ := crypto.GenerateNewKey()
	os.Setenv("CHARON_ENCRYPTION_KEY", currentKey)
	defer os.Unsetenv("CHARON_ENCRYPTION_KEY")

	db := setupEncryptionTestDB(t)
	rotationService, _ := crypto.NewRotationService(db)
	securityService := services.NewSecurityService(db)
	defer securityService.Close()

	handler := NewEncryptionHandler(rotationService, securityService)
	router := setupEncryptionTestRouter(handler, true)

	// Test invalid page number (negative)
	w := httptest.NewRecorder()
	req, _ := http.NewRequest("GET", "/api/v1/admin/encryption/history?page=-1&limit=10", nil)
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusOK, w.Code)

	// Test limit exceeding max (should clamp)
	w = httptest.NewRecorder()
	req, _ = http.NewRequest("GET", "/api/v1/admin/encryption/history?page=1&limit=200", nil)
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusOK, w.Code)

	var response map[string]any
	_ = json.Unmarshal(w.Body.Bytes(), &response)
	// limit should not exceed 100
	assert.LessOrEqual(t, response["limit"].(float64), float64(100))
}

func TestEncryptionHandler_GetStatus_VersionInfo(t *testing.T) {
	gin.SetMode(gin.TestMode)

	currentKey, _ := crypto.GenerateNewKey()
	os.Setenv("CHARON_ENCRYPTION_KEY", currentKey)
	defer func() {
		os.Unsetenv("CHARON_ENCRYPTION_KEY")
	}()

	db := setupEncryptionTestDB(t)
	rotationService, _ := crypto.NewRotationService(db)
	securityService := services.NewSecurityService(db)
	defer securityService.Close()

	handler := NewEncryptionHandler(rotationService, securityService)
	router := setupEncryptionTestRouter(handler, true)

	w := httptest.NewRecorder()
	req, _ := http.NewRequest("GET", "/api/v1/admin/encryption/status", nil)
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusOK, w.Code)

	var status crypto.RotationStatus
	err := json.Unmarshal(w.Body.Bytes(), &status)
	assert.NoError(t, err)
	// Verify the status response has expected fields
	assert.True(t, status.CurrentVersion >= 1)
}

// =============================================================================
// Settings Handler - Additional Unique Coverage Tests
// =============================================================================

func TestSettingsHandler_TestPublicURL_RoleNotExists(t *testing.T) {
	gin.SetMode(gin.TestMode)

	db, err := gorm.Open(sqlite.Open(fmt.Sprintf("file:%s?mode=memory&cache=shared", t.Name())), &gorm.Config{})
	require.NoError(t, err)

	handler := NewSettingsHandler(db)

	router := gin.New()
	// Don't set any role
	router.POST("/test-url", handler.TestPublicURL)

	body := `{"url": "https://example.com"}`
	req, _ := http.NewRequest("POST", "/test-url", strings.NewReader(body))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusForbidden, w.Code)
}

func TestSettingsHandler_TestPublicURL_InvalidURLFormat(t *testing.T) {
	gin.SetMode(gin.TestMode)

	db, err := gorm.Open(sqlite.Open(fmt.Sprintf("file:%s?mode=memory&cache=shared", t.Name())), &gorm.Config{})
	require.NoError(t, err)

	handler := NewSettingsHandler(db)

	router := gin.New()
	router.Use(func(c *gin.Context) {
		c.Set("role", "admin")
		c.Next()
	})
	router.POST("/test-url", handler.TestPublicURL)

	body := `{"url": "not-a-valid-url"}`
	req, _ := http.NewRequest("POST", "/test-url", strings.NewReader(body))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestSettingsHandler_TestPublicURL_PrivateIPBlocked_Coverage(t *testing.T) {
	gin.SetMode(gin.TestMode)

	db, err := gorm.Open(sqlite.Open(fmt.Sprintf("file:%s?mode=memory&cache=shared", t.Name())), &gorm.Config{})
	require.NoError(t, err)

	handler := NewSettingsHandler(db)

	router := gin.New()
	router.Use(func(c *gin.Context) {
		c.Set("role", "admin")
		c.Next()
	})
	router.POST("/test-url", handler.TestPublicURL)

	// SSRF attempt with private IP
	body := `{"url": "http://192.168.1.1"}`
	req, _ := http.NewRequest("POST", "/test-url", strings.NewReader(body))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	// Should return 200 but with reachable=false due to SSRF protection
	assert.Equal(t, http.StatusOK, w.Code)
	var response map[string]any
	_ = json.Unmarshal(w.Body.Bytes(), &response)
	assert.False(t, response["reachable"].(bool))
}

func TestSettingsHandler_ValidatePublicURL_WithTrailingSlash(t *testing.T) {
	gin.SetMode(gin.TestMode)

	db, err := gorm.Open(sqlite.Open(fmt.Sprintf("file:%s?mode=memory&cache=shared", t.Name())), &gorm.Config{})
	require.NoError(t, err)

	handler := NewSettingsHandler(db)

	router := gin.New()
	router.Use(func(c *gin.Context) {
		c.Set("role", "admin")
		c.Next()
	})
	router.POST("/validate-url", handler.ValidatePublicURL)

	// URL with trailing slash (should normalize and may produce warning)
	body := `{"url": "https://example.com/"}`
	req, _ := http.NewRequest("POST", "/validate-url", strings.NewReader(body))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusOK, w.Code)
	var response map[string]any
	_ = json.Unmarshal(w.Body.Bytes(), &response)
	assert.True(t, response["valid"].(bool))
}

func TestSettingsHandler_ValidatePublicURL_MissingScheme(t *testing.T) {
	gin.SetMode(gin.TestMode)

	db, err := gorm.Open(sqlite.Open(fmt.Sprintf("file:%s?mode=memory&cache=shared", t.Name())), &gorm.Config{})
	require.NoError(t, err)

	handler := NewSettingsHandler(db)

	router := gin.New()
	router.Use(func(c *gin.Context) {
		c.Set("role", "admin")
		c.Next()
	})
	router.POST("/validate-url", handler.ValidatePublicURL)

	// Invalid URL (missing scheme)
	body := `{"url": "example.com"}`
	req, _ := http.NewRequest("POST", "/validate-url", strings.NewReader(body))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusBadRequest, w.Code)
	var response map[string]any
	_ = json.Unmarshal(w.Body.Bytes(), &response)
	assert.False(t, response["valid"].(bool))
}

// =============================================================================
// Audit Log Handler - Additional Coverage Tests
// =============================================================================

func TestAuditLogHandler_List_PaginationEdgeCases(t *testing.T) {
	gin.SetMode(gin.TestMode)

	dbPath := fmt.Sprintf("/tmp/test_audit_pagination_%d.db", time.Now().UnixNano())
	t.Cleanup(func() { _ = os.Remove(dbPath) })

	db, _ := gorm.Open(sqlite.Open(dbPath), &gorm.Config{})
	_ = db.AutoMigrate(&models.SecurityAudit{}, &models.DNSProvider{})

	// Create test audits
	for i := 0; i < 10; i++ {
		db.Create(&models.SecurityAudit{
			Actor:         "user1",
			Action:        fmt.Sprintf("action_%d", i),
			EventCategory: "test",
			Details:       "{}",
		})
	}

	secService := services.NewSecurityService(db)
	defer secService.Close()
	handler := NewAuditLogHandler(secService)

	router := gin.New()
	router.GET("/audit", handler.List)

	// Test with pagination
	w := httptest.NewRecorder()
	req, _ := http.NewRequest("GET", "/audit?page=2&limit=3", nil)
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusOK, w.Code)
}

func TestAuditLogHandler_List_CategoryFilter(t *testing.T) {
	gin.SetMode(gin.TestMode)

	dbPath := fmt.Sprintf("/tmp/test_audit_category_%d.db", time.Now().UnixNano())
	t.Cleanup(func() { _ = os.Remove(dbPath) })

	db, _ := gorm.Open(sqlite.Open(dbPath), &gorm.Config{})
	_ = db.AutoMigrate(&models.SecurityAudit{}, &models.DNSProvider{})

	// Create test audits with different categories
	db.Create(&models.SecurityAudit{
		Actor:         "user1",
		Action:        "action1",
		EventCategory: "encryption",
		Details:       "{}",
	})
	db.Create(&models.SecurityAudit{
		Actor:         "user2",
		Action:        "action2",
		EventCategory: "security",
		Details:       "{}",
	})

	secService := services.NewSecurityService(db)
	defer secService.Close()
	handler := NewAuditLogHandler(secService)

	router := gin.New()
	router.GET("/audit", handler.List)

	// Test with category filter
	w := httptest.NewRecorder()
	req, _ := http.NewRequest("GET", "/audit?category=encryption", nil)
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusOK, w.Code)
}

func TestAuditLogHandler_ListByProvider_DatabaseError(t *testing.T) {
	gin.SetMode(gin.TestMode)

	dbPath := fmt.Sprintf("/tmp/test_audit_db_error_%d.db", time.Now().UnixNano())
	t.Cleanup(func() { _ = os.Remove(dbPath) })

	db, _ := gorm.Open(sqlite.Open(dbPath), &gorm.Config{})
	_ = db.AutoMigrate(&models.SecurityAudit{}, &models.DNSProvider{})

	secService := services.NewSecurityService(db)
	defer secService.Close()
	handler := NewAuditLogHandler(secService)

	// Close DB to trigger error
	sqlDB, _ := db.DB()
	_ = sqlDB.Close()

	router := gin.New()
	router.GET("/audit/provider/:id", handler.ListByProvider)

	w := httptest.NewRecorder()
	req, _ := http.NewRequest("GET", "/audit/provider/1", nil)
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusInternalServerError, w.Code)
}

func TestAuditLogHandler_ListByProvider_InvalidProviderID(t *testing.T) {
	gin.SetMode(gin.TestMode)

	dbPath := fmt.Sprintf("/tmp/test_audit_invalid_id_%d.db", time.Now().UnixNano())
	t.Cleanup(func() { _ = os.Remove(dbPath) })

	db, _ := gorm.Open(sqlite.Open(dbPath), &gorm.Config{})
	_ = db.AutoMigrate(&models.SecurityAudit{}, &models.DNSProvider{})

	secService := services.NewSecurityService(db)
	defer secService.Close()
	handler := NewAuditLogHandler(secService)

	router := gin.New()
	router.GET("/audit/provider/:id", handler.ListByProvider)

	w := httptest.NewRecorder()
	req, _ := http.NewRequest("GET", "/audit/provider/invalid", nil)
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusBadRequest, w.Code)
}

// =============================================================================
// getActorFromGinContext Additional Coverage
// =============================================================================

func TestGetActorFromGinContext_InvalidUserIDType(t *testing.T) {
	gin.SetMode(gin.TestMode)

	router := gin.New()
	var capturedActor string
	router.Use(func(c *gin.Context) {
		c.Set("user_id", 123.45) // float - invalid type
		c.Next()
	})
	router.GET("/test", func(c *gin.Context) {
		capturedActor = getActorFromGinContext(c)
		c.Status(http.StatusOK)
	})

	w := httptest.NewRecorder()
	req, _ := http.NewRequest("GET", "/test", nil)
	router.ServeHTTP(w, req)

	// Should fall back to "system" for invalid type
	assert.Equal(t, "system", capturedActor)
}

// =============================================================================
// isAdmin Additional Coverage
// =============================================================================

func TestIsAdmin_NonAdminRole(t *testing.T) {
	gin.SetMode(gin.TestMode)

	router := gin.New()
	router.Use(func(c *gin.Context) {
		c.Set("user_role", "user") // Not admin
		c.Next()
	})
	router.GET("/test", func(c *gin.Context) {
		if isAdmin(c) {
			c.JSON(http.StatusOK, gin.H{"admin": true})
		} else {
			c.JSON(http.StatusForbidden, gin.H{"admin": false})
		}
	})

	w := httptest.NewRecorder()
	req, _ := http.NewRequest("GET", "/test", nil)
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusForbidden, w.Code)
}

// =============================================================================
// Credential Handler - Additional Coverage Tests
// =============================================================================

func setupCredentialHandlerTestWithCtx(t *testing.T) (*gin.Engine, *gorm.DB, *models.DNSProvider, context.Context) {
	os.Setenv("CHARON_ENCRYPTION_KEY", "MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY=")
	t.Cleanup(func() { os.Unsetenv("CHARON_ENCRYPTION_KEY") })

	gin.SetMode(gin.TestMode)
	router := gin.New()

	dbName := fmt.Sprintf("file:%s?mode=memory&cache=shared&_journal_mode=WAL", t.Name())
	db, err := gorm.Open(sqlite.Open(dbName), &gorm.Config{})
	require.NoError(t, err)

	t.Cleanup(func() {
		sqlDB, _ := db.DB()
		_ = sqlDB.Close()
	})

	err = db.AutoMigrate(
		&models.DNSProvider{},
		&models.DNSProviderCredential{},
		&models.SecurityAudit{},
	)
	require.NoError(t, err)

	testKey := "MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY="
	encryptor, _ := crypto.NewEncryptionService(testKey)

	creds := map[string]string{"api_token": "test-token"}
	credsJSON, _ := json.Marshal(creds)
	encrypted, _ := encryptor.Encrypt(credsJSON)

	provider := &models.DNSProvider{
		UUID:                 "test-uuid",
		Name:                 "Test Provider",
		ProviderType:         "cloudflare",
		Enabled:              true,
		UseMultiCredentials:  true,
		CredentialsEncrypted: encrypted,
		KeyVersion:           1,
	}
	db.Create(provider)

	credService := services.NewCredentialService(db, encryptor)
	credHandler := NewCredentialHandler(credService)

	router.GET("/api/v1/dns-providers/:id/credentials", credHandler.List)
	router.POST("/api/v1/dns-providers/:id/credentials", credHandler.Create)
	router.GET("/api/v1/dns-providers/:id/credentials/:cred_id", credHandler.Get)
	router.PUT("/api/v1/dns-providers/:id/credentials/:cred_id", credHandler.Update)
	router.DELETE("/api/v1/dns-providers/:id/credentials/:cred_id", credHandler.Delete)
	router.POST("/api/v1/dns-providers/:id/credentials/:cred_id/test", credHandler.Test)
	router.POST("/api/v1/dns-providers/:id/enable-multi-credentials", credHandler.EnableMultiCredentials)

	return router, db, provider, context.Background()
}

func TestCredentialHandler_Update_InvalidProviderType(t *testing.T) {
	router, db, _, _ := setupCredentialHandlerTestWithCtx(t)

	testKey := "MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY="
	encryptor, _ := crypto.NewEncryptionService(testKey)

	// Create provider with invalid type
	creds := map[string]string{"api_token": "test-token"}
	credsJSON, _ := json.Marshal(creds)
	encrypted, _ := encryptor.Encrypt(credsJSON)

	provider := &models.DNSProvider{
		UUID:                 "invalid-type-uuid",
		Name:                 "Invalid Type Provider",
		ProviderType:         "nonexistent-provider",
		Enabled:              true,
		UseMultiCredentials:  true,
		CredentialsEncrypted: encrypted,
		KeyVersion:           1,
	}
	db.Create(provider)

	// Create credential
	credService := services.NewCredentialService(db, encryptor)
	createReq := services.CreateCredentialRequest{
		Label:       "Original",
		Credentials: map[string]string{"api_token": "token"},
	}

	// This should fail because provider type doesn't exist
	_, err := credService.Create(context.Background(), provider.ID, createReq)
	if err != nil {
		// Expected - provider type validation fails
		return
	}

	// If it didn't fail, try update with bad credentials
	updateBody := `{"label":"Updated","credentials":{"invalid_field":"value"}}`
	url := fmt.Sprintf("/api/v1/dns-providers/%d/credentials/1", provider.ID)
	req, _ := http.NewRequest("PUT", url, strings.NewReader(updateBody))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestCredentialHandler_List_DatabaseClosed(t *testing.T) {
	os.Setenv("CHARON_ENCRYPTION_KEY", "MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY=")
	defer os.Unsetenv("CHARON_ENCRYPTION_KEY")

	gin.SetMode(gin.TestMode)
	router := gin.New()

	dbName := fmt.Sprintf("file:%s?mode=memory&cache=shared", t.Name())
	db, _ := gorm.Open(sqlite.Open(dbName), &gorm.Config{})
	_ = db.AutoMigrate(&models.DNSProvider{}, &models.DNSProviderCredential{})

	testKey := "MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY="
	encryptor, _ := crypto.NewEncryptionService(testKey)

	credService := services.NewCredentialService(db, encryptor)
	credHandler := NewCredentialHandler(credService)

	router.GET("/api/v1/dns-providers/:id/credentials", credHandler.List)

	// Close DB to trigger error
	sqlDB, _ := db.DB()
	_ = sqlDB.Close()

	req, _ := http.NewRequest("GET", "/api/v1/dns-providers/1/credentials", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusInternalServerError, w.Code)
}

// =============================================================================
// Settings Handler - MaskPasswordForTest Coverage (unique test name)
// =============================================================================

func TestSettingsHandler_MaskPasswordForTestFunction(t *testing.T) {
	tests := []struct {
		name     string
		password string
		expected string
	}{
		{"empty string", "", ""},
		{"non-empty password", "secret123", "********"},
		{"already masked", "********", "********"},
		{"single char", "x", "********"},
	}

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

// =============================================================================
// Credential Handler - Additional Update/Delete Error Paths (unique names)
// =============================================================================

func TestCredentialHandler_Update_NotFoundError(t *testing.T) {
	router, _, provider, _ := setupCredentialHandlerTestWithCtx(t)

	updateBody := `{"label":"Updated","credentials":{"api_token":"new-token"}}`
	url := fmt.Sprintf("/api/v1/dns-providers/%d/credentials/9999", provider.ID)
	req, _ := http.NewRequest("PUT", url, strings.NewReader(updateBody))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusNotFound, w.Code)
	assert.Contains(t, w.Body.String(), "not found")
}

func TestCredentialHandler_Update_MalformedJSON(t *testing.T) {
	router, _, provider, _ := setupCredentialHandlerTestWithCtx(t)

	url := fmt.Sprintf("/api/v1/dns-providers/%d/credentials/1", provider.ID)
	req, _ := http.NewRequest("PUT", url, strings.NewReader("invalid json"))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestCredentialHandler_Update_BadCredentialID(t *testing.T) {
	router, _, provider, _ := setupCredentialHandlerTestWithCtx(t)

	url := fmt.Sprintf("/api/v1/dns-providers/%d/credentials/invalid", provider.ID)
	req, _ := http.NewRequest("PUT", url, strings.NewReader(`{}`))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusBadRequest, w.Code)
	assert.Contains(t, w.Body.String(), "Invalid credential ID")
}

func TestCredentialHandler_Delete_NotFoundError(t *testing.T) {
	router, _, provider, _ := setupCredentialHandlerTestWithCtx(t)

	url := fmt.Sprintf("/api/v1/dns-providers/%d/credentials/9999", provider.ID)
	req, _ := http.NewRequest("DELETE", url, nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusNotFound, w.Code)
}

func TestCredentialHandler_Delete_BadCredentialID(t *testing.T) {
	router, _, provider, _ := setupCredentialHandlerTestWithCtx(t)

	url := fmt.Sprintf("/api/v1/dns-providers/%d/credentials/invalid", provider.ID)
	req, _ := http.NewRequest("DELETE", url, nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestCredentialHandler_Test_BadCredentialID(t *testing.T) {
	router, _, provider, _ := setupCredentialHandlerTestWithCtx(t)

	url := fmt.Sprintf("/api/v1/dns-providers/%d/credentials/invalid/test", provider.ID)
	req, _ := http.NewRequest("POST", url, nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestCredentialHandler_EnableMultiCredentials_BadProviderID(t *testing.T) {
	router, _, _, _ := setupCredentialHandlerTestWithCtx(t)

	req, _ := http.NewRequest("POST", "/api/v1/dns-providers/invalid/enable-multi-credentials", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusBadRequest, w.Code)
}

// =============================================================================
// Encryption Handler - Additional Validate Success Test
// =============================================================================

func TestEncryptionHandler_Validate_AdminSuccess(t *testing.T) {
	gin.SetMode(gin.TestMode)

	currentKey, _ := crypto.GenerateNewKey()
	os.Setenv("CHARON_ENCRYPTION_KEY", currentKey)
	defer os.Unsetenv("CHARON_ENCRYPTION_KEY")

	db := setupEncryptionTestDB(t)
	rotationService, _ := crypto.NewRotationService(db)
	securityService := services.NewSecurityService(db)
	defer securityService.Close()

	handler := NewEncryptionHandler(rotationService, securityService)
	router := setupEncryptionTestRouter(handler, true)

	w := httptest.NewRecorder()
	req, _ := http.NewRequest("POST", "/api/v1/admin/encryption/validate", nil)
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusOK, w.Code)
}
