//
//  FederalPlayer.swift
//  PadelClub
//
//  Created by Razmig Sarkissian on 01/03/2024.
//

import Foundation

class FederalPlayer: Decodable {
    var rank: Int
    var lastName: String
    var firstName: String
    var country: String
    var license: String
    var points: Double?
    var assimilation: String
    var tournamentCount: Int?
    var ligue: String
    var clubCode: String
    var club: String
    var isMale: Bool
    
    
    // MARK: - Nationnalite
    struct Nationnalite: Hashable, Codable {
        let code, codeFov: String
    }

    required init(from decoder: Decoder) throws {
        enum CodingKeys: String, CodingKey {
            case nom
            case prenom
            case licence
            case meilleurClassement
            case nationnalite
            case anneeNaissance
            case codeClub
            case nomClub
            case nomLigue
            case rang
            case progression
            case points
            case nombreDeTournois
            case assimile
        }
        
        let container = try decoder.container(keyedBy: CodingKeys.self)

        isMale = (decoder.userInfo[.maleData] as? Bool) == true

        let _lastName = try container.decode(String.self, forKey: .nom)
        let _firstName = try container.decode(String.self, forKey: .prenom)
        lastName = _lastName
        firstName = _firstName
        if let lic = try? container.decodeIfPresent(Int.self, forKey: .licence) {
            license = String(lic)
        } else {
            license = ""
        }
            
        let nationnalite = try container.decode(Nationnalite.self, forKey: .nationnalite)
        country = nationnalite.code
        //meilleurClassement = try container.decode(Int.self, forKey: .meilleurClassement)
        //anneeNaissance = try container.decode(Int.self, forKey: .anneeNaissance)
        clubCode = try container.decode(String.self, forKey: .codeClub)
        club = try container.decode(String.self, forKey: .nomClub)
        ligue = try container.decode(String.self, forKey: .nomLigue)
        rank = try container.decode(Int.self, forKey: .rang)
        //progression = try? container.decodeIfPresent(Int.self, forKey: .progression)
        let pointsAsInt = try? container.decodeIfPresent(Int.self, forKey: .points)
        if let pointsAsInt {
            points = Double(pointsAsInt)
        } else {
            points = nil
        }
        tournamentCount = try? container.decodeIfPresent(Int.self, forKey: .nombreDeTournois)
        let assimile = try container.decode(Bool.self, forKey: .assimile)
        assimilation = assimile ? "Oui" : "Non"

    }
    
    func exportToCSV() -> String {
        let pointsString = points != nil ? String(Int(points!)) : ""
        let tournamentCountString = tournamentCount != nil ? String(tournamentCount!) : ""
        let strippedLicense = license.strippedLicense ?? ""
        let line = ";\(rank);\(lastName);\(firstName);\(country);\(strippedLicense);\(pointsString);\(assimilation);\(tournamentCountString);\(ligue);\(formatNumbers(clubCode));\(club);"
        return line
    }

    func formatNumbers(_ input: String) -> String {
        // Insert spaces at appropriate positions
        let formattedString = insertSeparator(input, separator: " ", every: [2, 4])
        return formattedString
    }

    func insertSeparator(_ input: String, separator: String, every positions: [Int]) -> String {
        var modifiedString = input
        // Adjust for the index shift caused by inserting characters
        var offset = 0
        // Insert separator at specified positions
        for position in positions {
            let index = modifiedString.index(modifiedString.startIndex, offsetBy: position + offset)
            modifiedString.insert(contentsOf: separator, at: index)
            // Increase offset to adjust for the inserted character
            offset += separator.count
        }
        return modifiedString
    }
        
    /*
     ;RANG;NOM;PRENOM;Nationalité;N° Licence;POINTS;Assimilation;NB. DE TOURNOIS JOUES;LIGUE;CODE CLUB;CLUB;
     */
    
    var isManPlayer: Bool {
        isMale
    }

    var isAssimilated: Bool {
        assimilation == "Oui"
    }
    
    var currentRank: Int {
        rank
    }
    
    init?(_ data: String, isMale: Bool = false) {
        self.isMale = isMale

        var result = data.components(separatedBy: .newlines).map { $0.trimmed }
        result = result.reversed().drop(while: {
            $0.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
        }).reversed() as [String]
        
        result = Array(result.drop(while: {
            $0.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
        }))

        //print(result)
        if result.count < 11 {
            return nil
        }
        if let _rank = Int(result[0]) {
            rank = _rank
        } else {
            return nil
        }
        lastName = result[1]
        firstName = result[2]
        
        country = result[3]
        license = result[4]
        
//        let matches = result[5].matches(of: try! Regex("[0-9]{1,5}\\.00"))
//
//        if matches.count == 1 {
//            let pts = result[5][matches.first!.range]
//            points = Double(pts.replacingOccurrences(of: ",", with: "."))
//            if pts.count < result[5].count {
//
//            }
//        }
//
        points = Double(result[5].replacingOccurrences(of: ",", with: "."))
        assimilation = result[6]
        tournamentCount = Int(result[7])
        ligue = result[8]
        clubCode = result[9]
        club = result[10]
    }

    static func anonymousCount(mostRecentDateAvailable: Date?) async -> Int? {
        let context = PersistenceController.shared.localContainer.newBackgroundContext()
        let importedPlayerFetchRequest = ImportedPlayer.fetchRequest()
        var predicate = NSPredicate(format: "lastName == %@ && firstName == %@", "", "")
        if let mostRecentDateAvailable {
            predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate, NSPredicate(format: "importDate == %@", mostRecentDateAvailable as CVarArg)])
        }
        importedPlayerFetchRequest.predicate = predicate
        let count = try? context.count(for: importedPlayerFetchRequest)
        return count
    }
    
    static func lastRank(mostRecentDateAvailable: Date?, man: Bool) async -> (Int, Int?)? {
        let context = PersistenceController.shared.localContainer.newBackgroundContext()
        let lastPlayerFetch = ImportedPlayer.fetchRequest()
        lastPlayerFetch.sortDescriptors = [NSSortDescriptor(keyPath: \ImportedPlayer.rank, ascending: false)]
        var predicate = NSPredicate(format: "male == \(man)")
        if let mostRecentDateAvailable {
            predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate, NSPredicate(format: "importDate == %@", mostRecentDateAvailable as CVarArg)])
        }
        lastPlayerFetch.predicate = predicate
        let count = try? context.count(for: lastPlayerFetch)
        do {
            if let lr = try context.fetch(lastPlayerFetch).first?.rank {
                let fetch = ImportedPlayer.fetchRequest()
                var rankPredicate = NSPredicate(format: "rank == %i", lr)
                if let mostRecentDateAvailable {
                    rankPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [rankPredicate, NSPredicate(format: "importDate == %@", mostRecentDateAvailable as CVarArg)])
                }
                fetch.predicate = rankPredicate

                let lastPlayersCount = try context.count(for: fetch)
                return (Int(lr) + Int(lastPlayersCount) - 1, count)
            }
        } catch {
            print("ImportedPlayer.fetchRequest", error)
        }
        
        return nil
    }

}

extension CodingUserInfoKey {
    static let maleData = Self(rawValue: "maleData")!
}
