//
//  GameViewController.swift
//  Privyet
//
//  Created by Amy Bowersox on 5/23/20.
//  Copyright © 2020 Erbosoft Metaverse Design Solutions. All rights reserved.
//

import UIKit
import SpriteKit
import GameplayKit

class GameViewController: UIViewController, PrivyetDelegate, UIGestureRecognizerDelegate {
    var scene: GameScene!
    var privyet: Privyet!
    var panPointReference: CGPoint?

    @IBOutlet weak var scoreLabel: UILabel!
    @IBOutlet weak var levelLabel: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // Configure the view
        let skView = view as! SKView
        skView.isMultipleTouchEnabled = false
        
        // Create and configure the scene
        scene = GameScene(size: skView.bounds.size)
        scene.scaleMode = .aspectFill
        
        scene.tick = didTick
        
        privyet = Privyet()
        privyet.delegate = self
        privyet.beginGame()
        
        // Present the scene
        skView.presentScene(scene)
    }

    override var prefersStatusBarHidden: Bool {
        return true
    }
    
    // Called when the user taps the screen
    @IBAction func didTap(_ sender: UITapGestureRecognizer) {
        privyet.rotateShape()
    }
    
    // Called when the user slides their finger across the screen
    @IBAction func didPan(_ sender: UIPanGestureRecognizer) {
        let currentPoint = sender.translation(in: self.view)
        if let originalPoint = panPointReference {
            if abs(currentPoint.x - originalPoint.x) > (BlockSize * 0.9) {
                if sender.velocity(in: self.view).x > CGFloat(0) {
                    privyet.moveShapeRight()
                    panPointReference = currentPoint
                } else {
                    privyet.moveShapeLeft()
                    panPointReference = currentPoint
                }
            }
        } else if sender.state == .began {
            panPointReference = currentPoint
        }
    }
    
    // Called when the user swipes the screen in a downward direction
    @IBAction func didSwipe(_ sender: UISwipeGestureRecognizer) {
        privyet.dropShape()
    }
    
    // Used to allow multiple gesture recognizers to be used simultaneously
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
    
    // Used to prioritize one gesture recognizer over another
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        if gestureRecognizer is UISwipeGestureRecognizer {
            if otherGestureRecognizer is UIPanGestureRecognizer {
                return true
            }
        } else if gestureRecognizer is UIPanGestureRecognizer {
            if otherGestureRecognizer is UITapGestureRecognizer {
                return true
            }
        }
        return false
    }
    
    // Called once per game tick (interval over which blocks drop)
    func didTick() {
        privyet.letShapeFall()
    }
    
    // Advances the "next' and "falling" shapes and places them on the screen
    func nextShape() {
        let newShapes = privyet.newShape()
        guard let fallingShape = newShapes.fallingShape else {
            return
        }
        self.scene.addPreviewShapeToScene(shape: newShapes.nextShape!) { }
        self.scene.movePreviewShape(shape: fallingShape) {
            self.view.isUserInteractionEnabled = true
            self.scene.startTicking()
        }
    }
    
    // Called when the game starts
    func gameDidBegin(privyet: Privyet) {
        levelLabel.text = "\(privyet.level)"
        scoreLabel.text = "\(privyet.score)"
        scene.tickLengthMillis = TickLengthLevelOne
        
        // The following is false when restarting a new game
        if privyet.nextShape != nil && privyet.nextShape!.blocks[0].sprite == nil {
            scene.addPreviewShapeToScene(shape: privyet.nextShape!) {
                self.nextShape()
            }
        } else {
            nextShape()
        }
    }
    
    // Called when the game ends
    func gameDidEnd(privyet: Privyet) {
        view.isUserInteractionEnabled = false
        scene.stopTicking()
        scene.playSound(sound: "Sounds/gameover.mp3")
        scene.animateCollapsingLines(linesToRemove: privyet.removeAllBlocks(), fallenBlocks: privyet.removeAllBlocks()) {
            privyet.beginGame()
        }
    }
    
    // Called when the game advances in level (gets faster)
    func gameDidLevelUp(privyet: Privyet) {
        levelLabel.text = "\(privyet.level)"
        if scene.tickLengthMillis >= 100 {
            scene.tickLengthMillis -= 100
        } else if scene.tickLengthMillis >= 50 {
            scene.tickLengthMillis -= 50
        }
        scene.playSound(sound: "Sounds/levelup.mp3")
    }
    
    // Called when a shape is "dropped"
    func gameShapeDidDrop(privyet: Privyet) {
        scene.stopTicking()
        scene.redrawShape(shape: privyet.fallingShape!) {
            privyet.letShapeFall()
        }
        scene.playSound(sound: "Sounds/drop.mp3")
    }
    
    // Called when a shape "lands" on top of existing blocks or at the bottom of the bucket
    func gameShapeDidLand(privyet: Privyet) {
        scene.stopTicking()
        self.view.isUserInteractionEnabled = false
        let removedLines = privyet.removeCompletedLines()
        if removedLines.linesRemoved.count > 0 {
            self.scoreLabel.text = "\(privyet.score)"
            scene.animateCollapsingLines(linesToRemove: removedLines.linesRemoved, fallenBlocks: removedLines.fallenBlocks) {
                self.gameShapeDidLand(privyet: privyet)
            }
            self.scene.playSound(sound: "Sounds/bomb.mp3")
        } else {
            nextShape()
        }
    }
    
    // Called when a shape moves on the screen
    func gameShapeDidMove(privyet: Privyet) {
        scene.redrawShape(shape: privyet.fallingShape!) { }
    }
}
