//
//  GameController.swift
//  TTTKit
//
//  Created by Shadowfacts on 12/21/22.
//

import Foundation
import Combine

public class GameController: ObservableObject {
    
    @Published public private(set) var state: State
    @Published public private(set) var board: SuperTicTacToeBoard
    
    public init() {
        self.state = .playAnywhere(.x)
        self.board = SuperTicTacToeBoard()
    }
    
    init(state: State, board: SuperTicTacToeBoard) {
        self.state = state
        self.board = board
    }
    
    public func play(on subBoard: (column: Int, row: Int), column: Int, row: Int) {
        guard board.getSubBoard(column: subBoard.column, row: subBoard.row)[column, row] == nil else {
            return
        }
        let activePlayer: Mark
        switch state {
        case .playAnywhere(let mark):
            activePlayer = mark
        case .playSpecific(let mark, column: subBoard.column, row: subBoard.row):
            activePlayer = mark
        default:
            return
        }
        
        board.play(mark: activePlayer, subBoard: subBoard, column: column, row: row)
        
        if let win = board.win {
            state = .end(.won(win))
        } else if board.tied {
            state = .end(.tie)
        } else {
            let nextSubBoard = board.getSubBoard(column: column, row: row)
            if nextSubBoard.ended {
                state = .playAnywhere(activePlayer.next)
            } else {
                state = .playSpecific(activePlayer.next, column: column, row: row)
            }
        }
    }
    
    private func canPlay(on subBoard: (column: Int, row: Int)) -> Bool {
        switch state {
        case .playAnywhere(_):
            return true
        case .playSpecific(_, column: subBoard.column, row: subBoard.row):
            return true
        default:
            return false
        }
    }
    
}

public extension GameController {
    enum State {
        case playAnywhere(Mark)
        case playSpecific(Mark, column: Int, row: Int)
        case end(Result)
        
        public var displayName: String {
            switch self {
            case .playAnywhere(_):
                return "Play anywhere"
            case .playSpecific(_, column: let col, row: let row):
                switch (col, row) {
                case (0, 0):
                    return "Play in the top left"
                case (1, 0):
                    return "Play in the top middle"
                case (2, 0):
                    return "Play in the top right"
                case (0, 1):
                    return "Play in the middle left"
                case (1, 1):
                    return "Play in the center"
                case (2, 1):
                    return "Play in the middle right"
                case (0, 2):
                    return "Play in the bottom left"
                case (1, 2):
                    return "Play in the bottom middle"
                case (2, 2):
                    return "Play in the bottom right"
                default:
                    fatalError()
                }
            case .end(.tie):
                return "It's a tie!"
            case .end(.won(let win)):
                switch win.mark {
                case .x:
                    return "X wins!"
                case .o:
                    return "O wins!"
                }
            }
        }
    }
}

public extension GameController {
    enum Result {
        case won(Win)
        case tie
    }
}
