Imports System.Drawing
Imports System.Windows.Forms

Public Class Form1
    Inherits Form

    Private deck As New List(Of Card)
    Private discardPile As New List(Of Card)
    Private drawPilePanel As Panel
    Private discardPilePanel As Panel
    Private playerHandPanel As Panel
    Private meldAreaPanel As Panel
    Private WithEvents btnDraw As Button
    Private WithEvents btnTakeDiscard As Button
    Private WithEvents btnMeld As Button
    Private WithEvents btnDiscard As Button

    Private playerHand As New List(Of Card)
    Private playerMelds As New List(Of List(Of Card))

    Private currentPlayerIndex As Integer = 0
    Private gameStarted As Boolean = False

    Public Sub New()
        Me.Text = "Canasta Card Game"
        Me.Size = New Size(1200, 800)
        Me.StartPosition = FormStartPosition.CenterScreen

        InitializeGame()
        SetupControls()
        StartNewGame()
    End Sub

    Private Class Card
        Public Property Suit As String
        Public Property Rank As String
        Public Property Value As Integer
        Public Property IsWild As Boolean
        Public Property IsJoker As Boolean
        Public Property IsRedThree As Boolean
        Public Property Button As Button

        Public Sub New(suit As String, rank As String)
            Me.Suit = suit
            Me.Rank = rank
            Me.IsJoker = (rank = "Joker")
            Me.IsRedThree = (rank = "3" AndAlso (suit = "Hearts" OrElse suit = "Diamonds"))

            If IsJoker Then
                Me.Value = 50
                Me.IsWild = True
            ElseIf rank = "2" Then
                Me.Value = 20
                Me.IsWild = True
            ElseIf rank = "A" Then
                Me.Value = 20
            ElseIf rank = "K" OrElse rank = "Q" OrElse rank = "J" OrElse rank = "10" Then
                Me.Value = 10
            ElseIf rank = "9" OrElse rank = "8" OrElse rank = "7" OrElse rank = "6" OrElse rank = "5" OrElse rank = "4" Then
                Me.Value = 5
            ElseIf rank = "3" AndAlso Not IsRedThree Then
                Me.Value = 5
            ElseIf IsRedThree Then
                Me.Value = 100 ' Bonus points
            End If
        End Sub

        Public Overrides Function ToString() As String
            Return $"{Rank} of {Suit}"
        End Function
    End Class

    Private Sub InitializeGame()
        ' Create two decks (standard Canasta uses two decks)
        Dim suits() As String = {"Hearts", "Diamonds", "Clubs", "Spades"}
        Dim ranks() As String = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"}

        ' Add two decks
        For deckNum As Integer = 1 To 2
            For Each suit In suits
                For Each rank In ranks
                    deck.Add(New Card(suit, rank))
                Next
            Next

            ' Add 4 Jokers (2 per deck)
            For j As Integer = 1 To 2
                deck.Add(New Card("Joker", "Joker"))
            Next
        Next
    End Sub

    Private Sub SetupControls()
        ' Draw pile panel
        drawPilePanel = New Panel With {
            .Location = New Point(50, 50),
            .Size = New Size(100, 150),
            .BackColor = Color.DarkGreen,
            .BorderStyle = BorderStyle.FixedSingle
        }
        Me.Controls.Add(drawPilePanel)

        ' Discard pile panel
        discardPilePanel = New Panel With {
            .Location = New Point(200, 50),
            .Size = New Size(100, 150),
            .BackColor = Color.LightGray,
            .BorderStyle = BorderStyle.FixedSingle
        }
        Me.Controls.Add(discardPilePanel)

        ' Player hand panel
        playerHandPanel = New Panel With {
            .Location = New Point(50, 250),
            .Size = New Size(1100, 150),
            .BackColor = Color.LightBlue,
            .BorderStyle = BorderStyle.FixedSingle,
            .AutoScroll = True
        }
        Me.Controls.Add(playerHandPanel)

        ' Meld area panel
        meldAreaPanel = New Panel With {
            .Location = New Point(50, 450),
            .Size = New Size(1100, 250),
            .BackColor = Color.Beige,
            .BorderStyle = BorderStyle.FixedSingle,
            .AutoScroll = True
        }
        Me.Controls.Add(meldAreaPanel)

        ' Buttons
        btnDraw = New Button With {
            .Text = "Draw Card",
            .Location = New Point(350, 50),
            .Size = New Size(100, 40),
            .Enabled = True
        }
        Me.Controls.Add(btnDraw)

        btnTakeDiscard = New Button With {
            .Text = "Take Discard",
            .Location = New Point(350, 100),
            .Size = New Size(100, 40),
            .Enabled = False
        }
        Me.Controls.Add(btnTakeDiscard)

        btnMeld = New Button With {
            .Text = "Make Meld",
            .Location = New Point(350, 150),
            .Size = New Size(100, 40),
            .Enabled = False
        }
        Me.Controls.Add(btnMeld)

        btnDiscard = New Button With {
            .Text = "Discard Card",
            .Location = New Point(350, 200),
            .Size = New Size(100, 40),
            .Enabled = False
        }
        Me.Controls.Add(btnDiscard)

        ' Status label
        Dim lblStatus As New Label With {
            .Text = "Game Status: Ready",
            .Location = New Point(500, 50),
            .Size = New Size(300, 30),
            .Font = New Font("Arial", 12)
        }
        Me.Controls.Add(lblStatus)
    End Sub

    Private Sub StartNewGame()
        ' Shuffle deck
        ShuffleDeck()

        ' Deal initial cards
        DealInitialCards()

        ' Setup discard pile
        SetupDiscardPile()

        ' Update display
        UpdateDisplay()

        gameStarted = True
    End Sub

    Private Sub ShuffleDeck()
        Dim rnd As New Random()
        deck = deck.OrderBy(Function(x) rnd.Next()).ToList()
    End Sub

    Private Sub DealInitialCards()
        playerHand.Clear()

        ' Deal 11 cards to player
        For i As Integer = 1 To 11
            If deck.Count > 0 Then
                playerHand.Add(deck(0))
                deck.RemoveAt(0)
            End If
        Next
    End Sub

    Private Sub SetupDiscardPile()
        discardPile.Clear()

        ' Draw first card to start discard pile
        If deck.Count > 0 Then
            discardPile.Add(deck(0))
            deck.RemoveAt(0)
        End If
    End Sub

    Private Sub UpdateDisplay()
        ' Clear all panels
        drawPilePanel.Controls.Clear()
        discardPilePanel.Controls.Clear()
        playerHandPanel.Controls.Clear()
        meldAreaPanel.Controls.Clear()

        ' Draw pile - show back of cards
        If deck.Count > 0 Then
            Dim lblDrawCount As New Label With {
                .Text = $"Draw: {deck.Count}",
                .Location = New Point(10, 10),
                .ForeColor = Color.White,
                .Font = New Font("Arial", 10)
            }
            drawPilePanel.Controls.Add(lblDrawCount)

            ' Draw a card back
            Dim cardBack As New Button With {
                .Text = "Deck",
                .Location = New Point(10, 40),
                .Size = New Size(80, 100),
                .BackColor = Color.Blue,
                .ForeColor = Color.White,
                .Font = New Font("Arial", 8)
            }
            AddHandler cardBack.Click, AddressOf DrawCard_Click
            drawPilePanel.Controls.Add(cardBack)
        End If

        ' Discard pile - show top card
        If discardPile.Count > 0 Then
            Dim topCard As Card = discardPile.Last()
            Dim discardBtn As New Button With {
                .Text = $"{topCard.Rank}{vbCrLf}{topCard.Suit}",
                .Location = New Point(10, 40),
                .Size = New Size(80, 100),
                .BackColor = GetCardColor(topCard),
                .ForeColor = Color.Black,
                .Font = New Font("Arial", 8),
                .Tag = topCard
            }
            AddHandler discardBtn.Click, AddressOf DiscardPile_Click
            discardPilePanel.Controls.Add(discardBtn)
        End If

        ' Player hand
        Dim xPos As Integer = 10
        For i As Integer = 0 To playerHand.Count - 1
            Dim card As Card = playerHand(i)

            ' Create button for each card
            Dim cardBtn As New Button With {
                .Text = $"{card.Rank}{vbCrLf}{card.Suit}",
                .Location = New Point(xPos, 10),
                .Size = New Size(70, 120),
                .BackColor = GetCardColor(card),
                .ForeColor = Color.Black,
                .Font = New Font("Arial", 8),
                .Tag = card
            }
            AddHandler cardBtn.Click, AddressOf PlayerCard_Click
            playerHandPanel.Controls.Add(cardBtn)

            xPos += 75
        Next

        ' Melds
        xPos = 10
        For Each meld In playerMelds
            Dim meldPanel As New Panel With {
                .Location = New Point(xPos, 10),
                .Size = New Size(200, 100),
                .BackColor = Color.LightGreen,
                .BorderStyle = BorderStyle.FixedSingle
            }

            Dim meldXPos As Integer = 5
            For Each card In meld
                Dim meldCardBtn As New Button With {
                    .Text = $"{card.Rank}{vbCrLf}{card.Suit}",
                    .Location = New Point(meldXPos, 10),
                    .Size = New Size(50, 80),
                    .BackColor = GetCardColor(card),
                    .ForeColor = Color.Black,
                    .Font = New Font("Arial", 7)
                }
                meldPanel.Controls.Add(meldCardBtn)
                meldXPos += 55
            Next

            meldAreaPanel.Controls.Add(meldPanel)
            xPos += 210
        Next

        ' Update button states
        UpdateButtonStates()
    End Sub

    Private Function GetCardColor(card As Card) As Color
        If card.Suit = "Hearts" OrElse card.Suit = "Diamonds" Then
            Return Color.LightPink
        ElseIf card.Suit = "Joker" Then
            Return Color.Purple
        Else
            Return Color.LightGray
        End If
    End Function

    Private Sub UpdateButtonStates()
        btnTakeDiscard.Enabled = (discardPile.Count > 0 AndAlso playerHand.Count > 0)
        btnMeld.Enabled = (playerHand.Count >= 3)
        btnDiscard.Enabled = (playerHand.Count > 0)
    End Sub

    ' Event Handlers
    Private Sub DrawCard_Click(sender As Object, e As EventArgs)
        If deck.Count > 0 Then
            playerHand.Add(deck(0))
            deck.RemoveAt(0)
            UpdateDisplay()
        End If
    End Sub

    Private Sub DiscardPile_Click(sender As Object, e As EventArgs)
        If discardPile.Count > 0 Then
            ' Take the entire discard pile (Canasta rule)
            playerHand.AddRange(discardPile)
            discardPile.Clear()
            UpdateDisplay()
        End If
    End Sub

    Private Sub PlayerCard_Click(sender As Object, e As EventArgs)
        Dim btn As Button = DirectCast(sender, Button)
        Dim card As Card = DirectCast(btn.Tag, Card)

        ' Highlight selected card
        If btn.BackColor = GetCardColor(card) Then
            btn.BackColor = Color.Yellow
        Else
            btn.BackColor = GetCardColor(card)
        End If
    End Sub

    Private Sub btnDraw_Click(sender As Object, e As EventArgs) Handles btnDraw.Click
        DrawCard_Click(sender, e)
    End Sub

    Private Sub btnTakeDiscard_Click(sender As Object, e As EventArgs) Handles btnTakeDiscard.Click
        DiscardPile_Click(sender, e)
    End Sub

    Private Sub btnMeld_Click(sender As Object, e As EventArgs) Handles btnMeld.Click
        ' Find selected cards
        Dim selectedCards As New List(Of Card)

        For Each ctrl As Control In playerHandPanel.Controls
            If TypeOf ctrl Is Button Then
                Dim btn As Button = DirectCast(ctrl, Button)
                If btn.BackColor = Color.Yellow AndAlso btn.Tag IsNot Nothing Then
                    selectedCards.Add(DirectCast(btn.Tag, Card))
                End If
            End If
        Next

        ' Check if valid meld (at least 3 cards of same rank or wild cards)
        If selectedCards.Count >= 3 Then
            ' Basic validation - check if all cards are same rank or wild
            Dim baseRank As String = selectedCards(0).Rank
            Dim isValidMeld As Boolean = True

            For Each card In selectedCards
                If Not card.IsWild AndAlso card.Rank <> baseRank Then
                    isValidMeld = False
                    Exit For
                End If
            Next

            If isValidMeld Then
                ' Remove from hand and add to melds
                For Each card In selectedCards
                    playerHand.Remove(card)
                Next

                playerMelds.Add(selectedCards)
                UpdateDisplay()
            Else
                MessageBox.Show("Invalid meld! Cards must be of same rank or wild cards.")
            End If
        Else
            MessageBox.Show("Select at least 3 cards for a meld!")
        End If
    End Sub

    Private Sub btnDiscard_Click(sender As Object, e As EventArgs) Handles btnDiscard.Click
        ' Find selected card
        Dim selectedCard As Card = Nothing

        For Each ctrl As Control In playerHandPanel.Controls
            If TypeOf ctrl Is Button Then
                Dim btn As Button = DirectCast(ctrl, Button)
                If btn.BackColor = Color.Yellow AndAlso btn.Tag IsNot Nothing Then
                    selectedCard = DirectCast(btn.Tag, Card)
                    Exit For
                End If
            End If
        Next

        If selectedCard IsNot Nothing Then
            ' Move card from hand to discard pile
            playerHand.Remove(selectedCard)
            discardPile.Add(selectedCard)
            UpdateDisplay()
        Else
            MessageBox.Show("Select a card to discard!")
        End If
    End Sub

    Private Function CalculateScore() As Integer
        Dim score As Integer = 0

        ' Score melds
        For Each meld In playerMelds
            For Each card In meld
                score += card.Value
            Next
        Next

        ' Score hand (negative)
        For Each card In playerHand
            score -= card.Value
        Next

        Return score
    End Function

    Protected Overrides Sub OnFormClosing(e As FormClosingEventArgs)
        If gameStarted Then
            Dim score As Integer = CalculateScore()
            MessageBox.Show($"Game Over! Final Score: {score}", "Canasta")
        End If
        MyBase.OnFormClosing(e)
    End Sub
End Class

' Entry point
Module Program
    Sub Main()
        Application.EnableVisualStyles()
        Application.SetCompatibleTextRenderingDefault(False)
        Application.Run(New Form1())
    End Sub
End Module
