//
//  GameView.swift
//  MagicCounter
//
//  Created by Atridad Lahiji on 2025-12-06.
//

import SwiftUI
import UniformTypeIdentifiers

/**
 * Main game screen displaying the grid of players.
 *
 * - match: The match record to initialize the game state from.
 */
struct GameView: View {
    @EnvironmentObject var gameManager: GameManager
    @State private var gameState: GameState
    @State private var showingStopConfirmation = false
    @State private var selectedPlayerForCommander: PlayerState?
    @State private var draggedPlayer: PlayerState?
    
    init(match: MatchRecord) {
        self._gameState = State(initialValue: match.state)
    }
    
    var body: some View {
        ZStack {
            // Background
            LinearGradient(colors: [Color.black, Color.indigo.opacity(0.5)], startPoint: .top, endPoint: .bottom)
                .ignoresSafeArea()
            
            VStack(spacing: 0) {
                // Custom Toolbar
                HStack {
                    Button(action: { gameManager.activeMatch = nil }) {
                        Image(systemName: "xmark")
                            .font(.system(size: 16, weight: .bold))
                            .foregroundColor(.white)
                            .padding(10)
                            .background(.ultraThinMaterial)
                            .clipShape(Circle())
                    }
                    
                    Spacer()
                    
                    if gameState.stopped {
                        Text("Game Stopped")
                            .font(.headline)
                            .foregroundStyle(.red)
                            .padding(.horizontal, 12)
                            .padding(.vertical, 6)
                            .background(.ultraThinMaterial)
                            .cornerRadius(8)
                    } else if let winner = gameState.winner {
                        Text("Winner: \(winner.name)")
                            .font(.headline)
                            .foregroundStyle(.green)
                            .padding(.horizontal, 12)
                            .padding(.vertical, 6)
                            .background(.ultraThinMaterial)
                            .cornerRadius(8)
                    } else {
                        Text("Magic Counter")
                            .font(.headline)
                            .foregroundStyle(.white)
                    }
                    
                    Spacer()
                    
                    if !gameState.stopped && gameState.winner == nil {
                        Button(action: { showingStopConfirmation = true }) {
                            Image(systemName: "stop.fill")
                                .font(.system(size: 16, weight: .bold))
                                .foregroundColor(.white)
                                .padding(10)
                                .background(.ultraThinMaterial)
                                .clipShape(Circle())
                        }
                    } else {
                        Color.clear.frame(width: 40, height: 40)
                    }
                }
                .padding()
                .background(.ultraThinMaterial)
                
                // Players Grid
                GeometryReader { geometry in
                    let columns = [GridItem(.adaptive(minimum: 320), spacing: 24)]
                    ScrollView {
                        LazyVGrid(columns: columns, spacing: 24) {
                            ForEach(gameState.players) { player in
                                PlayerCell(
                                    player: player,
                                    gameState: gameState,
                                    isWinner: gameState.winner?.id == player.id,
                                    onUpdate: updatePlayer,
                                    onCommanderTap: { selectedPlayerForCommander = player },
                                    onScoop: { scoopPlayer(player) }
                                )
                                .frame(height: 260)
                                .onDrag {
                                    self.draggedPlayer = player
                                    return NSItemProvider(object: String(player.id) as NSString)
                                }
                                .onDrop(of: [.text], delegate: PlayerDropDelegate(item: player, items: $gameState.players, draggedItem: $draggedPlayer))
                            }
                        }
                        .padding(24)
                    }
                }
            }
        }
        .alert("Stop Game?", isPresented: $showingStopConfirmation) {
            Button("Cancel", role: .cancel) { }
            Button("Stop", role: .destructive) {
                gameManager.stopGame()
                gameState.stopped = true
            }
        } message: {
            Text("Are you sure you want to stop this game?")
        }
        .sheet(item: $selectedPlayerForCommander) { player in
            CommanderDamageView(
                targetPlayer: player,
                gameState: gameState,
                onUpdate: { updatedPlayer in
                    updatePlayer(player: updatedPlayer)
                }
            )
            .presentationDetents([.medium])
        }
        .onChange(of: gameState) { newState in
            if newState.winner != nil {
                Haptics.notification(.success)
            }
            gameManager.updateActiveGame(state: newState)
        }
    }
    
    private func updatePlayer(player: PlayerState) {
        if gameState.stopped || gameState.winner != nil { return }
        
        if let index = gameState.players.firstIndex(where: { $0.id == player.id }) {
            gameState.players[index] = player
        }
        
        // Update the sheet state if this is the player being edited to ensure the view refreshes
        if selectedPlayerForCommander?.id == player.id {
            selectedPlayerForCommander = player
        }
    }
    
    private func scoopPlayer(_ player: PlayerState) {
        if gameState.stopped || gameState.winner != nil { return }
        
        var newPlayer = player
        newPlayer.scooped = true
        updatePlayer(player: newPlayer)
    }
}

/**
 * Individual player cell component.
 *
 * - player: The player state to display.
 * - gameState: The global game state.
 * - isWinner: Whether this player is the winner.
 * - onUpdate: Callback to update the player state.
 * - onCommanderTap: Callback when commander damage button is tapped.
 * - onScoop: Callback when scoop action is triggered.
 */
struct PlayerCell: View {
    let player: PlayerState
    let gameState: GameState
    let isWinner: Bool
    let onUpdate: (PlayerState) -> Void
    let onCommanderTap: () -> Void
    let onScoop: () -> Void
    
    @State private var showScoopConfirmation = false
    
    var body: some View {
        ZStack {
            RoundedRectangle(cornerRadius: 24)
                .fill(.ultraThinMaterial)
                .shadow(color: isWinner ? .green.opacity(0.5) : .black.opacity(0.2), radius: isWinner ? 20 : 10, x: 0, y: 5)
                .overlay(
                    RoundedRectangle(cornerRadius: 24)
                        .stroke(isWinner ? Color.green : Color.clear, lineWidth: 3)
                )
            
            VStack(spacing: 12) {
                // Header
                HStack {
                    Text(player.name)
                        .font(.headline)
                        .lineLimit(1)
                        .minimumScaleFactor(0.8)
                        .foregroundStyle(.primary)
                    Spacer()
                    
                    Button(action: { showScoopConfirmation = true }) {
                        Image(systemName: "flag.fill")
                            .foregroundStyle(.secondary)
                            .padding(4)
                    }
                }
                .padding(.horizontal)
                .padding(.top, 12)
                
                // Life
                LifeCounterControl(
                    value: player.life,
                    onDecrease: { adjustLife(by: -1) },
                    onIncrease: { adjustLife(by: 1) }
                )
                
                Spacer()
                
                // Counters Row
                HStack(spacing: 12) {
                    if gameState.trackPoison {
                        SmallCounterControl(
                            value: player.poison,
                            icon: "drop.fill",
                            color: .purple,
                            onDecrease: { adjustPoison(by: -1) },
                            onIncrease: { adjustPoison(by: 1) }
                        )
                    }
                    
                    if gameState.trackCommanderDamage {
                        Button(action: onCommanderTap) {
                            VStack(spacing: 2) {
                                Image(systemName: "shield.fill")
                                    .font(.caption)
                                Text("CMD")
                                    .font(.caption2.bold())
                            }
                            .frame(width: 44, height: 44)
                            .background(Color.orange.opacity(0.1))
                            .foregroundStyle(.orange)
                            .clipShape(Circle())
                        }
                    }
                }
                .padding(.bottom, 16)
            }
            
            if player.isEliminated && !isWinner {
                ZStack {
                    Color.black.opacity(0.6)
                        .cornerRadius(24)
                    Image(systemName: "xmark")
                        .font(.system(size: 60, weight: .bold))
                        .foregroundStyle(.white.opacity(0.8))
                }
            }
        }
        .opacity(player.isEliminated && !isWinner ? 0.8 : 1)
        .scaleEffect(isWinner ? 1.05 : 1)
        .animation(.spring, value: isWinner)
        .alert("Scoop?", isPresented: $showScoopConfirmation) {
            Button("Cancel", role: .cancel) { }
            Button("Scoop", role: .destructive) {
                Haptics.notification(.warning)
                onScoop()
            }
        } message: {
            Text("Are you sure you want to scoop?")
        }
    }
    
    private func adjustLife(by amount: Int) {
        if player.isEliminated { return }
        Haptics.play(.light)
        var newPlayer = player
        newPlayer.life += amount
        onUpdate(newPlayer)
        
        if newPlayer.isEliminated && !player.isEliminated {
            Haptics.notification(.error)
        }
    }
    
    private func adjustPoison(by amount: Int) {
        if player.isEliminated { return }
        Haptics.play(.light)
        var newPlayer = player
        newPlayer.poison = max(0, newPlayer.poison + amount)
        onUpdate(newPlayer)
        
        if newPlayer.isEliminated && !player.isEliminated {
            Haptics.notification(.error)
        }
    }
}

/**
 * Sheet for managing commander damage received by a player.
 *
 * - targetPlayer: The player receiving damage.
 * - gameState: The global game state.
 * - onUpdate: Callback to update the player state.
 */
struct CommanderDamageView: View {
    @Environment(\.dismiss) var dismiss
    let targetPlayer: PlayerState
    let gameState: GameState
    let onUpdate: (PlayerState) -> Void
    
    var body: some View {
        NavigationStack {
            List {
                ForEach(gameState.players.filter { $0.id != targetPlayer.id }) { attacker in
                    HStack {
                        Text(attacker.name)
                            .font(.headline)
                        Spacer()
                        HStack(spacing: 16) {
                            CircleButton(
                                icon: "minus",
                                color: .secondary,
                                action: { adjustCommanderDamage(attackerId: attacker.id, by: -1) }
                            )
                            
                            Text("\(targetPlayer.commanderDamages[attacker.id] ?? 0)")
                                .font(.title.bold())
                                .frame(minWidth: 40)
                                .multilineTextAlignment(.center)
                            
                            CircleButton(
                                icon: "plus",
                                color: .primary,
                                action: { adjustCommanderDamage(attackerId: attacker.id, by: 1) }
                            )
                        }
                    }
                    .padding(.vertical, 8)
                }
            }
            .navigationTitle("Commander Damage to \(targetPlayer.name)")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .confirmationAction) {
                    Button("Done") { dismiss() }
                }
            }
        }
    }
    
    private func adjustCommanderDamage(attackerId: Int, by amount: Int) {
        Haptics.play(.light)
        var newPlayer = targetPlayer
        var damages = newPlayer.commanderDamages
        let current = damages[attackerId] ?? 0
        damages[attackerId] = max(0, current + amount)
        newPlayer.commanderDamages = damages
        onUpdate(newPlayer)
        
        if newPlayer.isEliminated && !targetPlayer.isEliminated {
            Haptics.notification(.error)
        }
    }
}

struct PlayerDropDelegate: DropDelegate {
    let item: PlayerState
    @Binding var items: [PlayerState]
    @Binding var draggedItem: PlayerState?

    func performDrop(info: DropInfo) -> Bool {
        return true
    }

    func dropEntered(info: DropInfo) {
        guard let draggedItem = draggedItem else { return }
        if draggedItem.id != item.id {
            if let from = items.firstIndex(where: { $0.id == draggedItem.id }),
               let to = items.firstIndex(where: { $0.id == item.id }) {
                withAnimation {
                    let movedItem = items.remove(at: from)
                    items.insert(movedItem, at: to)
                }
            }
        }
    }
    
    func dropUpdated(info: DropInfo) -> DropProposal? {
        return DropProposal(operation: .move)
    }
}
