import Foundation
import Display
import AsyncDisplayKit
import Postbox
import SyncCore
import TelegramCore
import SwiftSignalKit
import AccountContext
import StickerResources
import ManagedAnimationNode

enum ReelValue {
    case rolling
    case bar
    case berries
    case lemon
    case seven
    case sevenWin
}

private func leftReelAnimationItem(value: ReelValue, immediate: Bool = false) -> ManagedAnimationItem {
    let frames: ManagedAnimationFrameRange? = immediate ? .still(.end) : nil
    switch value {
        case .rolling:
            return ManagedAnimationItem(source: .local("Slot_L_Spinning"), loop: true)
        case .bar:
            return ManagedAnimationItem(source: .local("Slot_L_Bar"), frames: frames, loop: false)
        case .berries:
            return ManagedAnimationItem(source: .local("Slot_L_Berries"), frames: frames, loop: false)
        case .lemon:
            return ManagedAnimationItem(source: .local("Slot_L_Lemon"), frames: frames, loop: false)
        case .seven:
            return ManagedAnimationItem(source: .local("Slot_L_7"), frames: frames, loop: false)
        case .sevenWin:
            return ManagedAnimationItem(source: .local("Slot_L_7_Win"), frames: frames, loop: false)
    }
}

private func centerReelAnimationItem(value: ReelValue, immediate: Bool = false) -> ManagedAnimationItem {
    let frames: ManagedAnimationFrameRange? = immediate ? .still(.end) : nil
    switch value {
        case .rolling:
            return ManagedAnimationItem(source: .local("Slot_M_Spinning"), frames: frames, loop: true)
        case .bar:
            return ManagedAnimationItem(source: .local("Slot_M_Bar"), frames: frames, loop: false)
        case .berries:
            return ManagedAnimationItem(source: .local("Slot_M_Berries"), frames: frames, loop: false)
        case .lemon:
            return ManagedAnimationItem(source: .local("Slot_M_Lemon"), frames: frames, loop: false)
        case .seven:
            return ManagedAnimationItem(source: .local("Slot_M_7"), frames: frames, loop: false)
        case .sevenWin:
            return ManagedAnimationItem(source: .local("Slot_M_7_Win"), frames: frames, loop: false)
    }
}

private func rightReelAnimationItem(value: ReelValue, immediate: Bool = false) -> ManagedAnimationItem {
    let frames: ManagedAnimationFrameRange? = immediate ? .still(.end) : nil
    switch value {
        case .rolling:
            return ManagedAnimationItem(source: .local("Slot_R_Spinning"), frames: frames, loop: true)
        case .bar:
            return ManagedAnimationItem(source: .local("Slot_R_Bar"), frames: frames, loop: false)
        case .berries:
            return ManagedAnimationItem(source: .local("Slot_R_Berries"), frames: frames, loop: false)
        case .lemon:
            return ManagedAnimationItem(source: .local("Slot_R_Lemon"), frames: frames, loop: false)
        case .seven:
            return ManagedAnimationItem(source: .local("Slot_R_7"), frames: frames, loop: false)
        case .sevenWin:
            return ManagedAnimationItem(source: .local("Slot_R_7_Win"), frames: frames, loop: false)
    }
}

final class SlotMachineAnimationNode: ASDisplayNode, GenericAnimatedStickerNode {
    private let context: AccountContext

    private let backNode: ManagedAnimationNode
    private let leftReelNode: ManagedAnimationNode
    private let centerReelNode: ManagedAnimationNode
    private let rightReelNode: ManagedAnimationNode
    private let frontNode: ManagedAnimationNode
    
    private var diceState: ManagedDiceAnimationState? = nil
    private let disposables = DisposableSet()
    
    init(context: AccountContext) {
        self.context = context
        
        let size = CGSize(width: 184.0, height: 184.0)
        self.backNode = ManagedAnimationNode(size: size)
        self.leftReelNode = ManagedAnimationNode(size: size)
        self.centerReelNode = ManagedAnimationNode(size: size)
        self.rightReelNode = ManagedAnimationNode(size: size)
        self.frontNode = ManagedAnimationNode(size: size)
        
        super.init()
        
        self.addSubnode(self.backNode)
        self.addSubnode(self.leftReelNode)
        self.addSubnode(self.centerReelNode)
        self.addSubnode(self.rightReelNode)
        self.addSubnode(self.frontNode)
    }
    
    deinit {
        self.disposables.dispose()
    }
    
    override func layout() {
        super.layout()
        
        self.backNode.frame = self.bounds
        self.leftReelNode.frame = self.bounds
        self.centerReelNode.frame = self.bounds
        self.rightReelNode.frame = self.bounds
        self.frontNode.frame = self.bounds
    }
    
    func setState(_ diceState: ManagedDiceAnimationState) {
        let previousState = self.diceState
        self.diceState = diceState
                
        if let previousState = previousState {
            switch previousState {
                case .rolling:
                    switch diceState {
                        case let .value(value, _):
                            let l: ReelValue
                            let c: ReelValue
                            let r: ReelValue
                            switch value {
                                case 1:
                                    l = .seven
                                    c = .berries
                                    r = .bar
                                case 2:
                                    l = .berries
                                    c = .berries
                                    r = .bar
                                case 3:
                                    l = .seven
                                    c = .berries
                                    r = .seven
                                case 4:
                                    l = .bar
                                    c = .lemon
                                    r = .seven
                                case 5:
                                    l = .berries
                                    c = .berries
                                    r = .berries
                                case 6:
                                    l = .sevenWin
                                    c = .sevenWin
                                    r = .sevenWin
                                default:
                                    l = .sevenWin
                                    c = .sevenWin
                                    r = .sevenWin
                            }
                            if value == 6 {
                                Queue.mainQueue().after(1.5) {
                                    self.backNode.trackTo(item: ManagedAnimationItem(source: .local("Slot_Back_Win"), loop: false))
                                }
                            } else {
                                self.backNode.trackTo(item: ManagedAnimationItem(source: .local("Slot_Back_Idle"), loop: false))
                            }
                            self.leftReelNode.trackTo(item: leftReelAnimationItem(value: l))
                            self.centerReelNode.trackTo(item: centerReelAnimationItem(value: c))
                            self.rightReelNode.trackTo(item: rightReelAnimationItem(value: r))
                            self.frontNode.trackTo(item: ManagedAnimationItem(source: .local("Slot_Front_Pull"), frames: .still(.end), loop: false))
                        case .rolling:
                            break
                    }
                case .value:
                    switch diceState {
                        case .rolling:
                            self.backNode.trackTo(item: ManagedAnimationItem(source: .local("Slot_Back_Idle"), loop: false))
                            self.leftReelNode.trackTo(item: leftReelAnimationItem(value: .rolling))
                            self.centerReelNode.trackTo(item: centerReelAnimationItem(value: .rolling))
                            self.rightReelNode.trackTo(item: rightReelAnimationItem(value: .rolling))
                            self.frontNode.trackTo(item: ManagedAnimationItem(source: .local("Slot_Front_Pull"), loop: false))
                        case .value:
                            break
                    }
            }
        } else {
            switch diceState {
                case let .value(value, immediate):
                    self.backNode.trackTo(item: ManagedAnimationItem(source: .local("Slot_Back_Idle"), loop: false))
                    
                    let l: ReelValue
                    let c: ReelValue
                    let r: ReelValue
                    switch value {
                        case 1:
                            l = .seven
                            c = .berries
                            r = .bar
                        case 2:
                            l = .berries
                            c = .berries
                            r = .bar
                        case 3:
                            l = .seven
                            c = .berries
                            r = .seven
                        case 4:
                            l = .bar
                            c = .lemon
                            r = .seven
                        case 5:
                            l = .berries
                            c = .berries
                            r = .berries
                        case 6:
                            l = .sevenWin
                            c = .sevenWin
                            r = .sevenWin
                        default:
                            l = .sevenWin
                            c = .sevenWin
                            r = .sevenWin
                    }
                    self.leftReelNode.trackTo(item: leftReelAnimationItem(value: l, immediate: immediate))
                    self.centerReelNode.trackTo(item: centerReelAnimationItem(value: c, immediate: immediate))
                    self.rightReelNode.trackTo(item: rightReelAnimationItem(value: r, immediate: immediate))
                    
                    let frames: ManagedAnimationFrameRange? = immediate ? .still(.end) : nil
                    self.frontNode.trackTo(item: ManagedAnimationItem(source: .local("Slot_Front_Pull"), frames: frames, loop: false))
                case .rolling:
                    self.backNode.trackTo(item: ManagedAnimationItem(source: .local("Slot_Back_Idle"), loop: false))
                    self.leftReelNode.trackTo(item: leftReelAnimationItem(value: .rolling))
                    self.centerReelNode.trackTo(item: centerReelAnimationItem(value: .rolling))
                    self.rightReelNode.trackTo(item: rightReelAnimationItem(value: .rolling))
                    self.frontNode.trackTo(item: ManagedAnimationItem(source: .local("Slot_Front_Pull"), loop: false))
            }
        }
    }
}