Imports System.IO
Imports System.Threading
Imports System.Windows.Forms
Imports System.Drawing
Imports System.Collections.Generic ' Dictionaryのためのインポート

Public Class ChatApp
    Inherits Form

    ' UI要素
    Private userName As String
    Private messageLog As RichTextBox ' RichTextBoxで色付きテキストを表示
    Private messageBox As TextBox
    Private sendButton As Button
    Private Shared logFilePath As String = "chatlog.txt"
    Private logWatcher As Thread

    ' ユーザーごとの色を管理するディクショナリ
    Private Shared userColors As New Dictionary(Of String, Color)

    ' 自分で送信した最後のメッセージを保持
    Private lastSentMessage As String = ""

    Public Sub New(user As String)
        ' ユーザー名を設定
        userName = user

        ' UIのセットアップ
        Me.Text = "Simple Chat App"
        Me.Width = 600
        Me.Height = 400

        ' メッセージログの表示領域
        messageLog = New RichTextBox()
        messageLog.Multiline = True
        messageLog.Dock = DockStyle.Top
        messageLog.Height = 250
        messageLog.ReadOnly = True
        messageLog.BackColor = Color.White
        messageLog.ForeColor = Color.Black
        Me.Controls.Add(messageLog)

        ' メッセージ入力ボックス
        messageBox = New TextBox()
        messageBox.Multiline = False
        messageBox.Dock = DockStyle.Bottom
        AddHandler messageBox.KeyDown, AddressOf HandleEnterKeyPress
        Me.Controls.Add(messageBox)

        ' 送信ボタン
        sendButton = New Button()
        sendButton.Text = "Send"
        sendButton.Dock = DockStyle.Bottom
        AddHandler sendButton.Click, AddressOf SendMessage
        Me.Controls.Add(sendButton)

        ' ユーザーの色を割り当て
        AssignUserColor(user)

        ' 過去のログを読み込んで表示
        If File.Exists(logFilePath) Then
            LoadExistingLog()
        End If

        ' ログの自動読み込みスレッドを開始
        logWatcher = New Thread(AddressOf WatchLogUpdates)
        logWatcher.IsBackground = True
        logWatcher.Start()
    End Sub

    ' ユーザーごとに色を割り当てる
    Private Sub AssignUserColor(user As String)
        If Not userColors.ContainsKey(user) Then
            ' ランダムな色を割り当てる
            Dim rand As New Random(user.GetHashCode())
            Dim userColor As Color = Color.FromArgb(rand.Next(50, 200), rand.Next(50, 200), rand.Next(50, 200))
            userColors(user) = userColor
        End If
    End Sub

    ' Enterキーでメッセージ送信
    Private Sub HandleEnterKeyPress(sender As Object, e As KeyEventArgs)
        If e.KeyCode = Keys.Enter Then
            SendMessage(sender, e)
            e.SuppressKeyPress = True ' Enterキーが押されても改行しないようにする
        End If
    End Sub

    ' メッセージを送信してログに追加
    Private Sub SendMessage(sender As Object, e As EventArgs)
        Dim message As String = messageBox.Text
        If Not String.IsNullOrEmpty(message) Then
            ' 文字列補間の代わりに文字列連結を使用
            Dim logEntry As String = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") & " " & userName & ": " & message & Environment.NewLine

            ' ファイルに保存
            File.AppendAllText(logFilePath, logEntry)

            ' メッセージログに追加(自動読み込みで重複表示されないようにする)
            lastSentMessage = logEntry ' 最後に送信したメッセージを記憶
            AppendMessageToLog(userName, message)

            ' メッセージボックスをクリア
            messageBox.Clear()
            ' メッセージボックスを再びアクティブにする
            messageBox.Focus()
        End If
    End Sub

    ' メッセージログにユーザーごとの色でメッセージを追加し、自動スクロール
    Private Sub AppendMessageToLog(user As String, message As String)
        If userColors.ContainsKey(user) Then
            Dim timestamp As String = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
            ' 文字列補間の代わりに連結
            Dim fullMessage As String = timestamp & " " & user & ": " & message & Environment.NewLine

            messageLog.SelectionStart = messageLog.TextLength
            messageLog.SelectionLength = 0
            messageLog.SelectionColor = userColors(user)
            messageLog.AppendText(fullMessage)
            messageLog.SelectionColor = messageLog.ForeColor ' デフォルトの色に戻す

            ' 新しいメッセージが追加されたらスクロール
            messageLog.ScrollToCaret()
        End If
    End Sub

    ' ログファイルの変更を監視し、更新があればメッセージログに反映
    Private Sub WatchLogUpdates()
        Dim lastReadLength As Long = 0

        ' 初期状態としてファイルの現在の長さを取得
        If File.Exists(logFilePath) Then
            lastReadLength = New FileInfo(logFilePath).Length
        End If

        While True
            Thread.Sleep(1000) ' 1秒ごとにチェック

            ' ファイルの長さを確認し、変更があれば読み込む
            Dim currentLength As Long = New FileInfo(logFilePath).Length
            If currentLength > lastReadLength Then
                ' 新しいテキストを読み込んで表示
                Dim newText As String = ReadNewLogEntries(lastReadLength)
                If Not String.IsNullOrEmpty(newText) Then
                    Me.Invoke(New MethodInvoker(Sub() AppendLogWithColors(newText)))
                End If
                lastReadLength = currentLength
            End If
        End While
    End Sub

    ' ログファイルから新規エントリを読み込む
    Private Function ReadNewLogEntries(lastReadLength As Long) As String
        Using fs As New FileStream(logFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
            fs.Seek(lastReadLength, SeekOrigin.Begin)
            Using sr As New StreamReader(fs)
                Return sr.ReadToEnd()
            End Using
        End Using
    End Function

    ' ログを色付きで表示し、自動スクロール
    Private Sub AppendLogWithColors(newText As String)
        Dim logEntries As String() = newText.Split(New String() {Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries)
        For Each entry In logEntries
            ' 最後に送信したメッセージと一致する場合はスキップ
            If entry.Trim() = lastSentMessage.Trim() Then
                Continue For
            End If

            ' ユーザー名を抽出して色を割り当て
            Dim parts As String() = entry.Split(New String() {": "}, 2, StringSplitOptions.None)
            If parts.Length = 2 Then
                Dim user As String = parts(0).Substring(20).Trim() ' タイムスタンプを除いてユーザー名を取得
                Dim message As String = parts(1).Trim()

                ' ユーザーの色を割り当ててログに追加
                If Not userColors.ContainsKey(user) Then
                    AssignUserColor(user)
                End If
                AppendMessageToLog(user, message)
            End If
        Next

        ' 新しいログが追加されたらスクロール
        messageLog.ScrollToCaret()
    End Sub

    ' 過去のログを色付きで読み込む
    Private Sub LoadExistingLog()
        Dim logEntries As String = File.ReadAllText(logFilePath)
        AppendLogWithColors(logEntries)
    End Sub

    <STAThread>
    Public Shared Sub Main()
        Application.EnableVisualStyles()

        ' ユーザー名を入力するフォーム
        Dim userName As String = InputBox("Enter your name:", "User Registration", "User")
        If String.IsNullOrEmpty(userName) Then
            ' MessageBoxの呼び出し方法を修正
            System.Windows.Forms.MessageBox.Show("A user name is required to start the chat.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
            Return
        End If

        ' チャットアプリケーションのインスタンスを作成
        Application.Run(New ChatApp(userName))
    End Sub
End Class