//
//  Characters.swift
//
//  Copyright © 2020 Apple Inc. All rights reserved.
//

import SpriteKit
import SPCScene


public class Hero: Graphic {
    static let sideIdle = #imageLiteral(resourceName: "turtle_64x128-1.png")
    static let walk = [#imageLiteral(resourceName: "turtle_64x128-1.png"), #imageLiteral(resourceName: "turtle_64x128-0.png")]
    static let walkScroll = [#imageLiteral(resourceName: "turtle_128-scroll-1.png"), #imageLiteral(resourceName: "turtle_128-scroll-0.png")]
    static let walkChest = [#imageLiteral(resourceName: "turtle_128-scrollChest-1.png"), #imageLiteral(resourceName: "turtle_128-scrollChest-0.png")]
    
    static let speed = 45.0   // points per second
    
    public init() {
        super.init(image: Image(with: Hero.sideIdle), name: "Hero")
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    
    // MARK - API
    
    public func turn() {
        self.xScale *= -1.0
    }
    
    public enum Loadout {
        case nothing, scroll, scrollChest
        
        var walkCycle: [Image] {
            switch self {
            case .scroll:
                return Hero.walkScroll.map { return Image(with: $0) }
            case .scrollChest:
                return Hero.walkChest.map { return Image(with: $0) }
            case .nothing:
                return Hero.walk.map { return Image(with: $0) }
            }
        }
    }
    public var holding: Loadout = .nothing {
        didSet {
            switch holding {
            case .scroll:
                self.texture = SKTexture(image: #imageLiteral(resourceName: "turtle_128-scroll-1.png"))
                self.size = texture!.size()
            case .scrollChest:
                self.texture = SKTexture(image: #imageLiteral(resourceName: "turtle_128-scrollChest-1.png"))
                self.size = texture!.size()
            case .nothing:
                self.texture = SKTexture(image: #imageLiteral(resourceName: "turtle_64x128-1.png"))
                self.size = texture!.size()
            }
        }
    }
    
    public func walk(distance: Double, completion: @escaping (() -> Void)) {
        self.animate(with: holding.walkCycle, fps: 4, loop: true)
        
        let move = SKAction.move(by: CGVector(dx: distance, dy: 0), duration: abs(distance)/Hero.speed)
        self.run(SKAction.sequence([SKAction.wait(forDuration: 0.2), move])) {
            DispatchQueue.main.async {
                completion()
            }
        }
    }
    
    public func approachHall(completion: @escaping (() -> Void)) {
        let ani = self.animation(with: holding.walkCycle, fps: 4, loop: false)
        
        let distance = 3*64.0-20.0
        let duration = abs(distance)/Hero.speed
        let numberRepeats = Int(duration / 0.5) + 1
        let walk = SKAction.group([ SKAction.repeat(ani, count: numberRepeats),  SKAction.move(by: CGVector(dx: distance, dy: 0), duration: duration)])

        let jumpUp = SKAction.run {
            self.animate(with: [self.holding.walkCycle[0]], fps: 10, loop: false)
        }
        
        let jumpDown = SKAction.run {
            self.animate(with: [self.holding.walkCycle[1]], fps: 10, loop: false)
        }
        
        let jump = SKAction.sequence([jumpUp, SKAction.move(by: CGVector(dx: 32.0, dy: 48.0), duration: 0.2), jumpDown, SKAction.move(by: CGVector(dx: 32.0, dy: -16.0), duration: 0.3)])
        
        let cont = SKAction.run {
            self.walk(distance: 200.0, completion: {})
        }
        
        self.run(SKAction.sequence([SKAction.wait(forDuration: 0.2), walk, jump, jump, jump, cont, SKAction.wait(forDuration: 2.5)])) {
            DispatchQueue.main.async {
                completion()
            }
        }
    }
}


public class Lizard : Graphic {
    static let side = #imageLiteral(resourceName: "lizard-side-128-0.png")
    static let idle = [#imageLiteral(resourceName: "lizard-side-128-1.png"), #imageLiteral(resourceName: "lizard-side-128-0.png")]
    
    public init() {
        super.init(image: Image(with: Lizard.side), name: "Hero")
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    
    // MARK - API
    
    public func turn() {
        self.xScale *= -1.0
    }
    
    public func idle() {
        let images = Lizard.idle.map { return Image(with: $0) }
        self.animate(with: images, fps: 2, loop: true)
    }
}


public class Swan : Graphic {
    static let side = #imageLiteral(resourceName: "swan-side-128_0.png")
    static let idle = [#imageLiteral(resourceName: "swan-side-128_1.png"), #imageLiteral(resourceName: "swan-side-128_0.png")]
    
    public init() {
        super.init(image: Image(with: Swan.side), name: "Swan")
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    
    // MARK - API
    
    public func turn() {
        self.xScale *= -1.0
    }
    
    public func idle() {
        let images = Swan.idle.map { return Image(with: $0) }
        self.animate(with: images, fps: 2, loop: true)
    }
}
