import SwiftUI
import AVFoundation

struct SharkCashoutView: View {
    @EnvironmentObject var gameState: GameState
    
    @State private var sharkAudio: AVAudioPlayer?
    @State private var plankAudio: AVAudioPlayer?
    
    @State private var currentPlank = 0
    @State private var bet = 0
    @State private var playing = false
    @State private var betIsZero = true
    @State private var notEnoughMoney = false
    @State private var distanceBetweenPlanks = CGFloat(0.0)
    @State private var jumping = false
    @State private var brokenPlanks = Array(repeating: false, count: 30)
    @State private var plankWinnings = Array(repeating: 0, count: 30)
    @State private var jumpAnimationTimer: Timer?
    @State private var personPosition = CGSize(width: 0.0, height: 0.0)
    @State private var planksAnimationTimer: Timer?
    @State private var planksPosition = CGFloat(0.0)
    @State private var sharkAnimationTimer: Timer?
    @State private var sharkPosition = CGFloat(0.0)
    @State private var personSprite = "Person Standing"
    @State private var sharkSprite = "Shark"
    @State private var loosing = false
    @State private var eaten = false
    @State private var lost = false
    
    let jumpDistancePerFrame = 5.0
    let totalJumpFrames = 40
    let totalSharkFrames = 50
    let sharkDistancePerFrame = 6.0
    
    func initializeSounds() {
        guard let url = Bundle.main.url(forResource: "Shark SFX", withExtension: "mp3") else {
            return
        }
        
        sharkAudio = try? AVAudioPlayer(contentsOf: url)
        
        guard let url = Bundle.main.url(forResource: "Plank SFX", withExtension: "mp3") else {
            return
        }
        
        plankAudio = try? AVAudioPlayer(contentsOf: url)
    }
    
    func generatePlanks() {
        var multiplier: Float
        
        for i in 0...29 {
            brokenPlanks[i] = (Int.random(in: 0...2) == 0)
            
            multiplier = 0.97 / (powf(0.77, Float(i + 1)))
            plankWinnings[i] = Int(Float(bet) * multiplier)
        }
    }
    
    func jumpOne() {
        planksAnimation(from: 1)
        jumpAnimation()
    }
    
    func jumpTwo() {
        planksAnimation(from: 2)
        jumpAnimation()
    }
    
    func checkPlank() {
        if !brokenPlanks[currentPlank - 1] {
            bet = plankWinnings[currentPlank - 1]
            
            if currentPlank == 30 {
                lost = true
            }
        } else {
            bet = 0
            loosing = true
            
            sharkAudio?.stop()
            sharkAudio?.currentTime = 0
            sharkAudio?.play()
            
            sharkAnimation()
        }
    }
    
    func jumpAnimation() {
        personSprite = "Person Jumping"
        
        jumpAnimationTimer?.invalidate()
        
        var distanceJumped = 0.0
        
        var frameCount = 0
        
        jumpAnimationTimer = Timer.scheduledTimer(withTimeInterval: 0.025, repeats: true) { timer in
            frameCount += 1
            
            if frameCount < (totalJumpFrames / 2) {
                distanceJumped -= jumpDistancePerFrame
            } else {
                distanceJumped += jumpDistancePerFrame
            }
            
            personPosition = CGSize(
                width: 0.0,
                height: distanceJumped
            )
            
            if frameCount > totalJumpFrames {
                personSprite = "Person Standing"
                timer.invalidate()
                jumping = false
                checkPlank()
                plankAudio?.stop()
                plankAudio?.currentTime = 0
                plankAudio?.play()
            }
        }
    }
    
    func planksAnimation(from planksJumped: Int) {
        planksAnimationTimer?.invalidate()
        
        var distanceMoved = 0.0
        
        var frameCount = 0
        
        let distancePerFrame = Double(planksJumped) * Double(distanceBetweenPlanks) / Double(totalJumpFrames)
        
        planksAnimationTimer = Timer.scheduledTimer(withTimeInterval: 0.025, repeats: true) { timer in
            frameCount += 1
            
            distanceMoved -= distancePerFrame
            
            planksPosition = CGFloat(distanceMoved)
            
            if frameCount + (planksJumped - 1) > totalJumpFrames {
                timer.invalidate()
                currentPlank += planksJumped
                planksPosition = 0.0
            }
        }
    }
    
    func sharkAnimation() {
        sharkAnimationTimer?.invalidate()
        
        var distanceLeaped = 0.0
        
        var frameCount = 0
        
        sharkAnimationTimer = Timer.scheduledTimer(withTimeInterval: 0.025, repeats: true) { timer in
            frameCount += 1
            
            if frameCount < (totalSharkFrames / 2) {
                distanceLeaped += sharkDistancePerFrame
            } else {
                distanceLeaped -= sharkDistancePerFrame
            }
            
            if frameCount == (totalSharkFrames / 2) {
                eaten = true
                sharkSprite = "Shark Biting"
            }
            
            sharkPosition = distanceLeaped
            
            if frameCount > totalSharkFrames {
                timer.invalidate()
                lost = true
            }
        }
    }
    
    func resetGame() {
        gameState.money += bet
        currentPlank = 0
        playing = false
        bet = 0
        betIsZero = true
        loosing = false
        eaten = false
        lost = false
        
        sharkSprite = "Shark"
        
        if (gameState.money < 100) {
            notEnoughMoney = true
        } else {
            notEnoughMoney = false
        }
    }
    
    var body: some View {
        ZStack {
            Image("Shark Cashout Cloth")
                .resizable()
                .scaledToFill()
            
            VStack {
                Text("$\(gameState.money)")
                    .foregroundColor(.black)
                    .font(.system(.title, design: .rounded)).bold()
                    .padding(10)
                    .background(Color.yellow)
                    .cornerRadius(10)
                    .padding(.bottom, 50)
                
                HStack {
                    GeometryReader { geometry in
                        ZStack {
                            VStack {
                                Image("Plank")
                                    .resizable()
                                    .scaledToFit()
                                    .frame(maxWidth: 200)
                                    .offset(x: -20.0 + planksPosition, y: 170.0)
                            }
                            .onAppear() {
                                distanceBetweenPlanks = geometry.size.width / 5.0
                            }
                            
                            VStack {
                                Image("Plank")
                                    .resizable()
                                    .scaledToFit()
                                    .frame(maxWidth: 200)
                                    .offset(x: -20.0 + planksPosition, y: 170.0)
                            }
                            .offset(x: distanceBetweenPlanks)
                            
                            VStack {
                                if currentPlank < 30 {
                                    ZStack {
                                        Image("Plank")
                                            .resizable()
                                            .scaledToFit()
                                            .frame(maxWidth: 200)
                                            .offset(x: -20.0, y: 170.0)
                                        if (playing) {
                                            Text("$\(plankWinnings[currentPlank])")
                                                .foregroundColor(.white)
                                                .font(.system(.title, design: .rounded)).bold()
                                                .padding(10)
                                                .background(Color.teal)
                                                .cornerRadius(20)
                                        }
                                    }
                                }
                            }
                            .offset(x: (distanceBetweenPlanks * 2.0) + planksPosition)
                            
                            VStack {
                                if currentPlank < 29 {
                                    ZStack {
                                        Image("Plank")
                                            .resizable()
                                            .scaledToFit()
                                            .frame(maxWidth: 200)
                                            .offset(x: -20.0, y: 170.0)
                                        if (playing) {
                                            Text("$\(plankWinnings[currentPlank + 1])")
                                                .foregroundColor(.white)
                                                .font(.system(.title, design: .rounded)).bold()
                                                .padding(10)
                                                .background(Color.teal)
                                                .cornerRadius(20)
                                        }
                                    }
                                }
                            }
                            .offset(x: (distanceBetweenPlanks * 3.0) + planksPosition)
                            
                            VStack {
                                if currentPlank < 28 {
                                    ZStack {
                                        Image("Plank")
                                            .resizable()
                                            .scaledToFit()
                                            .frame(maxWidth: 200)
                                            .offset(x: -20.0, y: 170.0)
                                        if (playing) {
                                            Text("$\(plankWinnings[currentPlank + 2])")
                                                .foregroundColor(.white)
                                                .font(.system(.title, design: .rounded)).bold()
                                                .padding(10)
                                                .background(Color.teal)
                                                .cornerRadius(20)
                                        }
                                    }
                                }
                            }
                            .offset(x: (distanceBetweenPlanks * 4.0) + planksPosition)
                            
                            VStack {
                                if currentPlank < 27 {
                                    ZStack {
                                        Image("Plank")
                                            .resizable()
                                            .scaledToFit()
                                            .frame(maxWidth: 200)
                                            .offset(x: -20.0, y: 170.0)
                                        if (playing) {
                                            Text("$\(plankWinnings[currentPlank + 3])")
                                                .foregroundColor(.white)
                                                .font(.system(.title, design: .rounded)).bold()
                                                .padding(10)
                                                .background(Color.teal)
                                                .cornerRadius(20)
                                        }
                                    }
                                }
                            }
                            .offset(x: (distanceBetweenPlanks * 5.0) + planksPosition)
                            
                            VStack {
                                if currentPlank < 26 {
                                    ZStack {
                                        Image("Plank")
                                            .resizable()
                                            .scaledToFit()
                                            .frame(maxWidth: 200)
                                            .offset(x: -20.0, y: 170.0)
                                        if (playing) {
                                            Text("$\(plankWinnings[currentPlank + 4])")
                                                .foregroundColor(.white)
                                                .font(.system(.title, design: .rounded)).bold()
                                                .padding(10)
                                                .background(Color.teal)
                                                .cornerRadius(20)
                                        }
                                    }
                                }
                            }
                            .offset(x: (distanceBetweenPlanks * 6.0) + planksPosition)
                            
                            if !eaten {
                                Image(personSprite)
                                    .resizable()
                                    .scaledToFit()
                                    .frame(maxWidth: 200)
                                    .offset(x: personPosition.width + distanceBetweenPlanks, y: personPosition.height)
                            }
                            
                            if loosing {
                                Image(sharkSprite)
                                    .resizable()
                                    .scaledToFit()
                                    .frame(maxWidth: 200)
                                    .offset(x: distanceBetweenPlanks, y: 150.0 - sharkPosition)
                            }
                        }
                    }
                }
                .frame(height: 450)
                
                HStack {
                    if (!playing) {
                        Button {
                            bet -= 100
                        } label: {
                            Text(" -  ")
                                .foregroundColor(.white)
                                .font(.system(.title3, design: .rounded)).bold()
                                .padding(5)
                                .background(Color.brown)
                                .cornerRadius(15)
                        }
                        .disabled(betIsZero)
                    }
                    
                    Text("$\(bet)")
                        .foregroundColor(.white)
                        .font(.system(.title2, design: .rounded)).bold()
                    
                    if (!playing) {
                        Button {
                            bet += 100
                        } label: {
                            Text(" +  ")
                                .foregroundColor(.white)
                                .font(.system(.title3, design: .rounded)).bold()
                                .padding(5)
                                .background(Color.brown)
                                .cornerRadius(15)
                        }
                        .disabled(notEnoughMoney)
                        
                        .onChange(of: bet) {
                            betIsZero = bet == 0
                            notEnoughMoney = (bet + 100) > gameState.money
                        }
                    }
                }
                
                Text("\n")
                
                HStack {
                    if (!playing) {
                        Button {
                            playing = true
                            
                            gameState.money -= bet
                            
                            generatePlanks()
                            
                            bet = 0
                        } label: {
                            Text("Play")
                                .foregroundColor(.black)
                                .font(.system(.title2, design: .rounded)).bold()
                                .padding(10)
                                .padding(.horizontal, 20)
                                .background(Color.red)
                                .cornerRadius(20)
                        }
                        .disabled(betIsZero)
                    } else if !lost {
                        Button {
                            jumping = true
                            
                            jumpOne()
                        } label: {
                            Text("Jump 1")
                                .foregroundColor(.black)
                                .font(.system(.title2, design: .rounded)).bold()
                                .padding(10)
                                .padding(.horizontal, 20)
                                .background(Color.yellow)
                                .cornerRadius(20)
                        }
                        .disabled(jumping || loosing)
                        
                        Button {
                            jumping = true
                            
                            jumpTwo()
                        } label: {
                            Text("Jump 2")
                                .foregroundColor(.black)
                                .font(.system(.title2, design: .rounded)).bold()
                                .padding(10)
                                .padding(.horizontal, 20)
                                .background(Color.orange)
                                .cornerRadius(20)
                        }
                        .disabled(jumping || loosing)
                        
                        Button {
                            resetGame()
                        } label: {
                            Text("Cashout")
                                .foregroundColor(.black)
                                .font(.system(.title2, design: .rounded)).bold()
                                .padding(10)
                                .padding(.horizontal, 20)
                                .background(Color.green)
                                .cornerRadius(20)
                        }
                        .disabled(jumping || loosing)
                    } else {
                        Button {
                            resetGame()
                        } label: {
                            Text("Continue")
                                .foregroundColor(.black)
                                .font(.system(.title2, design: .rounded)).bold()
                                .padding(10)
                                .padding(.horizontal, 20)
                                .background(Color.red)
                                .cornerRadius(20)
                        }
                    }
                }
            }
        }
        .onAppear() {
            if (gameState.money < 100) {
                notEnoughMoney = true
            } else {
                notEnoughMoney = false
            }
            
            initializeSounds()
        }
    }
}

#Preview {
    SharkCashoutView()
        .environmentObject(GameState())
}
