//
//  Carta.swift
//  poker
//
//  Created by Julio Hermosa on 4/13/20.
//  Copyright © 2020 Mobile Roshka. All rights reserved.
//

import Foundation
enum Palo: Int{
    //se crean los palos posibles en poker (el valor de los mismos no tienen significancia en el juego)
    case E = 1//espadas
    case T = 2//tréboles
    case C = 3//corazones
    case D = 4//diamantes
}
enum Jugada: Int{
    //se crean las combinaciones posibles con un valor que sirve para saber cual es la mejor jugada
    case EscaleraReal = 10
    case EscaleraColor = 9
    case Poker = 8
    case Full = 7
    case Color = 6
    case Escalera = 5
    case Trio = 4
    case ParDoble = 3
    case Par = 2
    case CartaAlta = 1
}


//se simula una baraja, que contiene hasta 52 cartas francesas
class Baraja{
    var cartas: [(Int, String)]? = []
    func crearBaraja(){
        for index1 in 1...13{
            for index2 in 1...4{ cartas!.append((index1,"\(Palo.init(rawValue: index2)!)"))
            }
            
        }
    }
}

//se simula que se extraen 5 cartas de una baraja para cada jugador
class Manos{
    var cartasEnMano: [(Int, String)] = []
    var cartasEnMesa: [(Int, String)] = []
    var baraja: Baraja = Baraja()
    var valoresOrdenados = [Int]()
    var palo = [String]()
    var nombreCarta = [String]()
    var nombreJugada:Jugada = Jugada(rawValue: 1)!
    private let escaleraAlAs: [Int] = [1, 10, 11, 12, 13]
    
    //función para extraer 2 cartas y guardar la información en arrays con los valores, el palo y el nombre de la carta en caso de ser A, J, Q y K
    //la función recibe como parámetro las cartas que aun no se extrajeron para que no se repitan
    func extraerCartasTexasHoldem(cartasDisponibles: Baraja)->[(Int, String)]{
        baraja = cartasDisponibles
        var randomNumber = Int.random(in: 0..<baraja.cartas!.count)
        cartasEnMano.append((baraja.cartas?[randomNumber])!)
        baraja.cartas?.remove(at: randomNumber)
        randomNumber = Int.random(in: 0..<baraja.cartas!.count)
        cartasEnMano.append((baraja.cartas?[randomNumber])!)
        baraja.cartas?.remove(at: randomNumber)
        
        nombrarCartas(cantidadCartas: 2)
        return cartasEnMano
    }
    
    func enMesa(cartasDisponibles: Baraja)->[(Int, String)]{
        baraja = cartasDisponibles
        for _ in 0...4 {
            let randomNumber = Int.random(in: 0..<baraja.cartas!.count)
            cartasEnMesa.append((baraja.cartas?[randomNumber])!)
            baraja.cartas?.remove(at: randomNumber)
        }
        return cartasEnMesa
    }
    
    //función para extraer 5 cartas y guardar la información en arrays con los valores, el palo y el nombre de la carta en caso de ser A, J, Q y K
    //la función recibe como parámetro las cartas que aun no se extrajeron para que no se repitan
    func extraerCartas(cartasDisponibles: Baraja){
        baraja = cartasDisponibles
        //cargamos las cartas a las manos y borramos de la baraja para que no se vuelvan a sacar
        let cantCartas = 5
        for _ in 0..<cantCartas{
            let randomNumber = Int.random(in: 0..<baraja.cartas!.count)
            cartasEnMano.append((baraja.cartas?[randomNumber])!)
            baraja.cartas?.remove(at: randomNumber)
        }
        nombrarCartas(cantidadCartas: cantCartas)
    }
    private func nombrarCartas(cantidadCartas: Int){
        
        for index in 0..<cantidadCartas{
        //se carga en el array el nombre de la carta, 1: A, 11:J, 12:Q y 13:K
            switch cartasEnMano[index].0 {
            case 1:
                nombreCarta.append("A")
            case 11:
                nombreCarta.append("J")
            case 12:
                nombreCarta.append("Q")
            case 13:
                nombreCarta.append("K")
            default: nombreCarta.append("\(cartasEnMano[index].0)")
            }
            
            //se cargan en arrays los valores numéricos y los palos de las cartas extraídas de la baraja
            valoresOrdenados.append(cartasEnMano[index].0)
            palo.append(cartasEnMano[index].1)
        }
        //ordenamos los valores, para determinar posteriormente si hay alguna combinación
        valoresOrdenados.sort()
        
    }

        //devuelve el nombre de la jugada segun la combinación de cartas, el array con los valores ordenados y el mayor en caso de haber una combinación
    func jugadas(valoresEnMesa: [Int],  palosEnMesa: [String])->(Jugada, [Int], Int){
        valoresOrdenados += valoresEnMesa
        palo += palosEnMesa
        valoresOrdenados.sort()
        var cartasOrdenadas = valoresOrdenados // copiamos su contenido para cambiar el orden en caso de tener ases, ya que los mismos tambien pueden valer 14 (se evalúa para cada caso)
        var mayorCombinacion = 0 //se utiliza en caso de necesitar desempate entre pares, doblepares, tríos, full y poker
        var contSecuencia = 1 //Para determinar si hay una escalera
        var contPalosIguales = 1 // para determinar si hay color
        var cantidad: [(Int, Int)] = [(1,0),(2,0),(3,0),(4,0),(5,0),(6,0),(7,0),(8,0),(9,0),(10,0),(11,0),(12,0),(13,0)] //se guarda el número de apariciones de cada valor, para determinar si hay pares, tríos o poker
        
        cantidad[valoresOrdenados[0]].1 += 1
        for index in 1...4{
                if valoresOrdenados[index] == valoresOrdenados[index-1]+1{
                    contSecuencia += 1
                    }
                if palo[index] == palo[index-1]{
                    contPalosIguales += 1
                }
                if cantidad[valoresOrdenados[index]-1].1 == 0{
                    cantidad[valoresOrdenados[index]-1].1 += 1
                }
                
                if valoresOrdenados[index] == valoresOrdenados[index - 1]{
                    cantidad[valoresOrdenados[index]-1].1 += 1
                }

        }
        if contPalosIguales == 5{
            nombreJugada = .Color
            if valoresOrdenados.contains(1){
                cartasOrdenadas = cartasOrdenadas.filter { $0 > 1}
                cartasOrdenadas.append(14)
            }
            
        }
        if contSecuencia == 5{
            nombreJugada = .Escalera
        }
        if valoresOrdenados == escaleraAlAs{
            nombreJugada = .Escalera
            if valoresOrdenados.contains(1){
                cartasOrdenadas = cartasOrdenadas.filter { $0 > 1}
                cartasOrdenadas.append(14)
            }
        }
        if nombreJugada == .Escalera && contPalosIguales == 5 {
            nombreJugada = .EscaleraColor
        }
        if valoresOrdenados == escaleraAlAs && contPalosIguales == 5 {
            nombreJugada = .EscaleraReal
            if valoresOrdenados.contains(1){
                cartasOrdenadas = cartasOrdenadas.filter { $0 > 1}
                cartasOrdenadas.append(14)
            }
        }
        let poker = cantidad.filter{ $0.1 == 4}
        let trio = cantidad.filter{ $0.1 == 3}
        let par = cantidad.filter{ $0.1 == 2}
        if par.count == 1{
            nombreJugada = .Par
            mayorCombinacion = par[0].0
        }
        if par.count == 2{
            nombreJugada = .ParDoble
            mayorCombinacion = par[1].0
        }
        if trio.count == 1{
            nombreJugada = .Trio
            mayorCombinacion = trio[0].0
        }
        if par.count == 1 && trio.count == 1{
            nombreJugada = .Full
            mayorCombinacion = trio[0].0
        }
        if poker.count == 1 {
            nombreJugada = .Poker
            mayorCombinacion = poker[0].0
        }
        if mayorCombinacion == 1{
            mayorCombinacion = 14
        }
        if nombreJugada == .CartaAlta{
            if valoresOrdenados.contains(1){
                cartasOrdenadas = cartasOrdenadas.filter { $0 > 1}
                cartasOrdenadas.append(14)
            }
        }

        return (nombreJugada, cartasOrdenadas, mayorCombinacion)
        
    }
  
    
    //eliminamos todas las modificaciones para empezar de nuevo el juego
    func barajarCartas(){
        baraja.cartas?.removeAll()
        cartasEnMano.removeAll()
        palo.removeAll()
        valoresOrdenados.removeAll()
        nombreCarta.removeAll()
        nombreJugada = .CartaAlta
    }
    
    
}
