import Foundation
import Vapor

typealias CardId = String

struct Card: Codable {
    
    enum Suit: Character, CaseIterable, Codable {
        case eichel = "E"
        case blatt = "B"
        case herz = "H"
        case schelln = "S"

        var ace: Card {
            .init(self, .ass)
        }
    }

    let symbol: Symbol
    
    let suit: Suit
    
    init(suit: Suit, symbol: Symbol) {
        self.suit = suit
        self.symbol = symbol
    }
    
    init(_ suit: Suit, _ symbol: Symbol) {
        self.suit = suit
        self.symbol = symbol
    }
    
    init?(id: CardId) {
        guard id.count == 2 else {
            return nil
        }
        guard let suit = Suit(rawValue: id.first!),
              let symbol = Symbol(id: id.last!) else {
                  return nil
              }
        self.suit = suit
        self.symbol = symbol
    }
    
    var id: CardId {
        "\(suit.rawValue)\(symbol.id)"
    }
    
    var points: Int {
        symbol.points
    }

    var playable: PlayableCard {
        .init(card: self, isPlayable: true)
    }

    var unplayable: PlayableCard {
        .init(card: self, isPlayable: false)
    }

    func playable(_ isPlayable: Bool) -> PlayableCard {
        .init(card: self, isPlayable: isPlayable)
    }
    
    static let allCards: Set<Card> = {
        let all = Card.Suit.allCases.map { suit in
            Card.Symbol.allCases.map { symbol in
                Card(suit: suit, symbol: symbol)
            }
        }.joined()
        return Set(all)
    }()
}

extension Card {

    func isTrump(in game: GameType) -> Bool {
        game.sortingType.isTrump(self)
    }
}

extension Card: CustomStringConvertible {
    
    var description: String {
        "\(suit) \(symbol)"
    }
}

extension Card: Hashable {
    
}
