' Secure Configuration Helper Class
' Reads connection strings and sensitive configuration from environment variables
' Supports .env file loading for development and system environment variables for production
' Fail-fast approach: throws clear exceptions if required variables are missing

Imports System
Imports System.IO
Imports System.Collections.Generic
Imports System.Configuration
Imports System.Web

Namespace RGBC_Forecast

    Public Class SecureConfig
        Private Shared _envVarsLoaded As Boolean = False
        Private Shared _envVars As New Dictionary(Of String, String)(StringComparer.OrdinalIgnoreCase)
        Private Shared _lockObject As New Object()

        ' Environment variable names (app-specific name per transcript; legacy name still supported)
        Private Const ENV_RGBC_FORECAST_CONNECTION_STRING As String = "RGBC_FORECAST_CONNECTION_STRING"
        Private Const ENV_SQL_CONNECTION_DEBUG As String = "SQL_CONNECTION_DEBUG"
        Private Const ENV_SQL_CONNECTION_RELEASE As String = "SQL_CONNECTION_RELEASE"
        Private Const ENV_SUPERBOWL_CONNECTION_STRING As String = "SUPERBOWL_CONNECTION_STRING"

        ''' <summary>
        ''' Loads environment variables from .env file (if exists) and system environment variables
        ''' Should be called once at application startup
        ''' Thread-safe: uses double-check locking pattern
        ''' </summary>
        Public Shared Sub LoadEnvironmentVariables()
            If _envVarsLoaded Then Return

            SyncLock _lockObject
                ' Double-check after acquiring lock
                If _envVarsLoaded Then Return

                ' First, load from .env file if it exists (development)
                LoadEnvFile()

                ' Then, load from system environment variables (overrides .env file values)
                LoadSystemEnvironmentVariables()

                _envVarsLoaded = True
            End SyncLock
        End Sub

        ''' <summary>
        ''' Loads environment variables from .env file in the root directory only (parent of application folder).
        ''' </summary>
        Private Shared Sub LoadEnvFile()
            Try
                Dim rootDir As String = Nothing
                Try
                    If HttpRuntime.AppDomainAppPath IsNot Nothing AndAlso HttpRuntime.AppDomainAppPath.Length > 0 Then
                        rootDir = Path.GetDirectoryName(HttpRuntime.AppDomainAppPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar))
                    End If
                Catch
                End Try
                If String.IsNullOrEmpty(rootDir) Then
                    Dim baseDir As String = AppDomain.CurrentDomain.BaseDirectory
                    If baseDir.EndsWith("\bin", StringComparison.OrdinalIgnoreCase) OrElse baseDir.EndsWith("/bin", StringComparison.OrdinalIgnoreCase) Then
                        baseDir = Path.GetDirectoryName(baseDir)
                    End If
                    rootDir = Path.GetDirectoryName(baseDir)
                End If
                If String.IsNullOrEmpty(rootDir) Then Return
                Dim envFilePath As String = Path.Combine(rootDir, ".env")
                If File.Exists(envFilePath) Then
                    Dim lines As String() = File.ReadAllLines(envFilePath)
                    For Each line As String In lines
                        ' Skip empty lines and comments
                        line = line.Trim()
                        If String.IsNullOrEmpty(line) OrElse line.StartsWith("#") Then
                            Continue For
                        End If

                        ' Parse KEY=VALUE format
                        Dim equalsIndex As Integer = line.IndexOf("="c)
                        If equalsIndex > 0 Then
                            Dim key As String = line.Substring(0, equalsIndex).Trim()
                            Dim value As String = line.Substring(equalsIndex + 1).Trim()

                            ' Remove quotes if present
                            If (value.StartsWith(""""c) AndAlso value.EndsWith(""""c)) OrElse
                               (value.StartsWith("'"c) AndAlso value.EndsWith("'"c)) Then
                                value = value.Substring(1, value.Length - 2)
                            End If

                            If Not String.IsNullOrEmpty(key) Then
                                _envVars(key) = value
                            End If
                        End If
                    Next
                End If
            Catch ex As Exception
                ' Log error but don't fail - system environment variables might still be available
                System.Diagnostics.Debug.WriteLine("Warning: Could not load .env file: " & ex.Message)
            End Try
        End Sub

        ''' <summary>
        ''' Loads environment variables from system environment
        ''' </summary>
        Private Shared Sub LoadSystemEnvironmentVariables()
            Try
                ' Load SQL connection strings
                Dim debugConn As String = Environment.GetEnvironmentVariable(ENV_SQL_CONNECTION_DEBUG)
                If Not String.IsNullOrEmpty(debugConn) Then
                    _envVars(ENV_SQL_CONNECTION_DEBUG) = debugConn
                End If

                Dim releaseConn As String = Environment.GetEnvironmentVariable(ENV_SQL_CONNECTION_RELEASE)
                If Not String.IsNullOrEmpty(releaseConn) Then
                    _envVars(ENV_SQL_CONNECTION_RELEASE) = releaseConn
                End If

                Dim forecastConn As String = Environment.GetEnvironmentVariable(ENV_RGBC_FORECAST_CONNECTION_STRING)
                If Not String.IsNullOrEmpty(forecastConn) Then
                    _envVars(ENV_RGBC_FORECAST_CONNECTION_STRING) = forecastConn
                End If
                Dim superbowlConn As String = Environment.GetEnvironmentVariable(ENV_SUPERBOWL_CONNECTION_STRING)
                If Not String.IsNullOrEmpty(superbowlConn) Then
                    _envVars(ENV_SUPERBOWL_CONNECTION_STRING) = superbowlConn
                End If
            Catch ex As Exception
                System.Diagnostics.Debug.WriteLine("Warning: Error loading system environment variables: " & ex.Message)
            End Try
        End Sub

        ''' <summary>
        ''' Gets a connection string by name from environment variables
        ''' Throws exception if variable is missing (fail-fast)
        ''' Thread-safe: ensures environment variables are loaded before access
        ''' </summary>
        Public Shared Function GetConnectionString(connectionName As String) As String
            ' Ensure environment variables are loaded (thread-safe)
            LoadEnvironmentVariables()

            ' Prefer app-specific env var (RGBC_FORECAST_CONNECTION_STRING), then legacy SUPERBOWL_CONNECTION_STRING.
            Dim envVarName As String = ""
            Select Case connectionName.ToUpper()
                Case "SUPERBOWLCONNECTIONSTRING", "SUPERBOWL_CONNECTION_STRING"
                    If _envVars.ContainsKey(ENV_RGBC_FORECAST_CONNECTION_STRING) AndAlso Not String.IsNullOrEmpty(_envVars(ENV_RGBC_FORECAST_CONNECTION_STRING)) Then
                        Return _envVars(ENV_RGBC_FORECAST_CONNECTION_STRING)
                    End If
                    envVarName = ENV_SUPERBOWL_CONNECTION_STRING
                Case Else
                    envVarName = connectionName.ToUpper().Replace(" ", "_")
            End Select

            If _envVars.ContainsKey(envVarName) AndAlso Not String.IsNullOrEmpty(_envVars(envVarName)) Then
                Return _envVars(envVarName)
            End If

            ' Fail-fast: throw clear exception if variable is missing
            Throw New ConfigurationErrorsException(
                "Required environment variable '" & envVarName & "' is not set. " &
                "Please set this variable in your .env file or system environment variables. " &
                "Connection name requested: " & connectionName)
        End Function

        ''' <summary>
        ''' Gets the SQL connection string for DEBUG mode
        ''' Throws exception if variable is missing (fail-fast)
        ''' Thread-safe: ensures environment variables are loaded before access
        ''' </summary>
        Public Shared Function GetSQLConnectionDebug() As String
            ' Ensure environment variables are loaded (thread-safe)
            LoadEnvironmentVariables()

            If _envVars.ContainsKey(ENV_SQL_CONNECTION_DEBUG) AndAlso Not String.IsNullOrEmpty(_envVars(ENV_SQL_CONNECTION_DEBUG)) Then
                Return _envVars(ENV_SQL_CONNECTION_DEBUG)
            End If

            ' Fail-fast: throw clear exception if variable is missing
            Throw New ConfigurationErrorsException(
                "Required environment variable '" & ENV_SQL_CONNECTION_DEBUG & "' is not set. " &
                "Please set this variable in your .env file or system environment variables.")
        End Function

        ''' <summary>
        ''' Gets the SQL connection string for RELEASE mode
        ''' Throws exception if variable is missing (fail-fast)
        ''' Thread-safe: ensures environment variables are loaded before access
        ''' </summary>
        Public Shared Function GetSQLConnectionRelease() As String
            ' Ensure environment variables are loaded (thread-safe)
            LoadEnvironmentVariables()

            If _envVars.ContainsKey(ENV_SQL_CONNECTION_RELEASE) AndAlso Not String.IsNullOrEmpty(_envVars(ENV_SQL_CONNECTION_RELEASE)) Then
                Return _envVars(ENV_SQL_CONNECTION_RELEASE)
            End If

            ' Fail-fast: throw clear exception if variable is missing
            Throw New ConfigurationErrorsException(
                "Required environment variable '" & ENV_SQL_CONNECTION_RELEASE & "' is not set. " &
                "Please set this variable in your .env file or system environment variables.")
        End Function

    End Class

End Namespace
