//
//  User.swift
//  PadelClub
//
//  Created by Laurent Morvillier on 21/02/2024.
//

import Foundation
import LeStorage

enum UserRight: Int, Codable {
    case none = 0
    case edition = 1
    case creation = 2
}

@Observable
class CustomUser: BaseCustomUser, UserBase {
    
//    static func resourceName() -> String { "users" }
//    static func tokenExemptedMethods() -> [HTTPMethod] { return [.post] }
//    static func filterByStoreIdentifier() -> Bool { return false }
//    static var relationshipNames: [String] = []
//
//    public var id: String = Store.randomId()
//    var lastUpdate: Date
//    public var username: String
//    public var email: String
//    var clubs: [String] = []
//    var umpireCode: String?
//    var licenceId: String?
//    var firstName: String
//    var lastName: String
//    var phone: String?
//    var country: String?
//    
//    var summonsMessageBody : String? = nil
//    var summonsMessageSignature: String? = nil
//    var summonsAvailablePaymentMethods: String? = nil
//    var summonsDisplayFormat: Bool = false
//    var summonsDisplayEntryFee: Bool = false
//    var summonsUseFullCustomMessage: Bool = false
//    var matchFormatsDefaultDuration: [MatchFormat: Int]? = nil
//    var bracketMatchFormatPreference: MatchFormat?
//    var groupStageMatchFormatPreference: MatchFormat?
//    var loserBracketMatchFormatPreference: MatchFormat?
//    var loserBracketMode: LoserBracketMode = .automatic
//
//    var deviceId: String?
    
    init(username: String, email: String, firstName: String, lastName: String, phone: String?, country: String?, loserBracketMode: LoserBracketMode = .automatic) {
        super.init(username: username, email: email, firstName: firstName, lastName: lastName, phone: phone, country: country, loserBracketMode: loserBracketMode)
        
        
//        self.lastUpdate = Date()
//        self.username = username
//        self.firstName = firstName
//        self.lastName = lastName
//        self.email = email
//        self.phone = phone
//        self.country = country
//        self.loserBracketMode = loserBracketMode
    }
    
    required init(from decoder: Decoder) throws {
        try super.init(from: decoder)
    }
    
    required public init() {
        super.init()
    }
    
    public func uuid() throws -> UUID  {
        if let uuid = UUID(uuidString: self.id) {
            return uuid
        }
        throw UUIDError.cantConvertString(string: self.id)
    }
    
    func currentPlayerData() -> ImportedPlayer? {
        guard let licenceId = self.licenceId?.strippedLicense else { return nil }
        let federalContext = PersistenceController.shared.localContainer.viewContext
        let fetchRequest = ImportedPlayer.fetchRequest()
        let predicate = NSPredicate(format: "license == %@", licenceId)
        fetchRequest.predicate = predicate
        return try? federalContext.fetch(fetchRequest).first
    }
    
    func defaultSignature(_ tournament: Tournament?) -> String {
        let fullName = tournament?.umpireCustomContact ?? fullName()
        return "Sportivement,\n\(fullName), votre JAP."
    }
    
    func fullName() -> String {
        [firstName, lastName].joined(separator: " ")
    }
    
    func hasTenupClubs() -> Bool {
        self.clubsObjects().filter({ $0.code != nil }).isEmpty == false
    }
    
    func hasFavoriteClubsAndCreatedClubs() -> Bool {
        clubsObjects(includeCreated: true).isEmpty == false
    }
    
    func setUserClub(_ userClub: Club) {
        self.clubs.insert(userClub.id, at: 0)
    }
    
    func clubsObjects(includeCreated: Bool = false) -> [Club] {
        return DataStore.shared.clubs.filter({ (includeCreated && $0.creator == id) || clubs.contains($0.id) })
    }
    
    func createdClubsObjectsNotFavorite() -> [Club] {
        return DataStore.shared.clubs.filter({ ($0.creator == id) && clubs.contains($0.id) == false })
    }

    func saveMatchFormatsDefaultDuration(_ matchFormat: MatchFormat, estimatedDuration: Int) {
        if estimatedDuration == matchFormat.defaultEstimatedDuration {
            matchFormatsDefaultDuration?.removeValue(forKey: matchFormat)
        } else {
            matchFormatsDefaultDuration = matchFormatsDefaultDuration ?? [MatchFormat: Int]()
            matchFormatsDefaultDuration?[matchFormat] = estimatedDuration
        }
    }
    
    func addClub(_ club: Club) {
        if !self.clubs.contains(where: { $0.id == club.id }) {
            self.clubs.append(club.id)
        }
    }
    
    func getSummonsMessageSignature() -> String? {
        if let summonsMessageSignature, summonsMessageSignature.isEmpty == false {
            return summonsMessageSignature
        } else {
            return nil
        }
    }
    
//    enum CodingKeys: String, CodingKey {
//        case _id = "id"
//        case _lastUpdate = "lastUpdate"
//        case _username = "username"
//        case _email = "email"
//        case _clubs = "clubs"
//        case _umpireCode = "umpireCode"
//        case _licenceId = "licenceId"
//        case _firstName = "firstName"
//        case _lastName = "lastName"
//        case _phone = "phone"
//        case _country = "country"
//        case _summonsMessageBody = "summonsMessageBody"
//        case _summonsMessageSignature = "summonsMessageSignature"
//        case _summonsAvailablePaymentMethods = "summonsAvailablePaymentMethods"
//        case _summonsDisplayFormat = "summonsDisplayFormat"
//        case _summonsDisplayEntryFee = "summonsDisplayEntryFee"
//        case _summonsUseFullCustomMessage = "summonsUseFullCustomMessage"
//        case _matchFormatsDefaultDuration = "matchFormatsDefaultDuration"
//        case _bracketMatchFormatPreference = "bracketMatchFormatPreference"
//        case _groupStageMatchFormatPreference = "groupStageMatchFormatPreference"
//        case _loserBracketMatchFormatPreference = "loserBracketMatchFormatPreference"
//        case _deviceId = "deviceId"
//        case _loserBracketMode = "loserBracketMode"
//    }
//    
//    public required init(from decoder: Decoder) throws {
//        let container = try decoder.container(keyedBy: CodingKeys.self)
//        
//        // Required properties
//        id = try container.decodeIfPresent(String.self, forKey: ._id) ?? Store.randomId()
//        lastUpdate = try container.decodeIfPresent(Date.self, forKey: ._lastUpdate) ?? Date()
//        username = try container.decode(String.self, forKey: ._username)
//        email = try container.decode(String.self, forKey: ._email)
//        firstName = try container.decode(String.self, forKey: ._firstName)
//        lastName = try container.decode(String.self, forKey: ._lastName)
//        
//        // Optional properties
//        clubs = try container.decodeIfPresent([String].self, forKey: ._clubs) ?? []
//        umpireCode = try container.decodeIfPresent(String.self, forKey: ._umpireCode)
//        licenceId = try container.decodeIfPresent(String.self, forKey: ._licenceId)
//        phone = try container.decodeIfPresent(String.self, forKey: ._phone)
//        country = try container.decodeIfPresent(String.self, forKey: ._country)
//        
//        // Summons-related properties
//        summonsMessageBody = try container.decodeIfPresent(String.self, forKey: ._summonsMessageBody)
//        summonsMessageSignature = try container.decodeIfPresent(String.self, forKey: ._summonsMessageSignature)
//        summonsAvailablePaymentMethods = try container.decodeIfPresent(String.self, forKey: ._summonsAvailablePaymentMethods)
//        summonsDisplayFormat = try container.decodeIfPresent(Bool.self, forKey: ._summonsDisplayFormat) ?? false
//        summonsDisplayEntryFee = try container.decodeIfPresent(Bool.self, forKey: ._summonsDisplayEntryFee) ?? false
//        summonsUseFullCustomMessage = try container.decodeIfPresent(Bool.self, forKey: ._summonsUseFullCustomMessage) ?? false
//        
//        // Match-related properties
//        matchFormatsDefaultDuration = try container.decodeIfPresent([MatchFormat: Int].self, forKey: ._matchFormatsDefaultDuration)
//        bracketMatchFormatPreference = try container.decodeIfPresent(MatchFormat.self, forKey: ._bracketMatchFormatPreference)
//        groupStageMatchFormatPreference = try container.decodeIfPresent(MatchFormat.self, forKey: ._groupStageMatchFormatPreference)
//        loserBracketMatchFormatPreference = try container.decodeIfPresent(MatchFormat.self, forKey: ._loserBracketMatchFormatPreference)
//        loserBracketMode = try container.decodeIfPresent(LoserBracketMode.self, forKey: ._loserBracketMode) ?? .automatic
//    }
//
//    func encode(to encoder: Encoder) throws {
//        var container = encoder.container(keyedBy: CodingKeys.self)
//        
//        try container.encode(id, forKey: ._id)
//        try container.encode(lastUpdate, forKey: ._lastUpdate)
//        try container.encode(username, forKey: ._username)
//        try container.encode(email, forKey: ._email)
//        try container.encode(clubs, forKey: ._clubs)
//        
//        try container.encode(umpireCode, forKey: ._umpireCode)
//        try container.encode(licenceId, forKey: ._licenceId)
//        try container.encode(firstName, forKey: ._firstName)
//        try container.encode(lastName, forKey: ._lastName)
//        try container.encode(phone, forKey: ._phone)
//        try container.encode(country, forKey: ._country)
//        try container.encode(summonsMessageBody, forKey: ._summonsMessageBody)
//        try container.encode(summonsMessageSignature, forKey: ._summonsMessageSignature)
//        try container.encode(summonsAvailablePaymentMethods, forKey: ._summonsAvailablePaymentMethods)
//        try container.encode(summonsDisplayFormat, forKey: ._summonsDisplayFormat)
//        try container.encode(summonsDisplayEntryFee, forKey: ._summonsDisplayEntryFee)
//        try container.encode(summonsUseFullCustomMessage, forKey: ._summonsUseFullCustomMessage)
//        
//        try container.encode(matchFormatsDefaultDuration, forKey: ._matchFormatsDefaultDuration)
//        try container.encode(bracketMatchFormatPreference, forKey: ._bracketMatchFormatPreference)
//        try container.encode(groupStageMatchFormatPreference, forKey: ._groupStageMatchFormatPreference)
//        try container.encode(loserBracketMatchFormatPreference, forKey: ._loserBracketMatchFormatPreference)
//        try container.encode(deviceId, forKey: ._deviceId)
//        
//        try container.encode(loserBracketMode, forKey: ._loserBracketMode)
//    }

    static func placeHolder() -> CustomUser {
        return CustomUser(username: "", email: "", firstName: "", lastName: "", phone: nil, country: nil)
    }

}

class UserCreationForm: CustomUser, UserPasswordBase {
    
    init(user: CustomUser, username: String, password: String, firstName: String, lastName: String, email: String, phone: String?, country: String?) {
        self.password = password
        super.init(username: username, email: email, firstName: firstName, lastName: lastName, phone: phone, country: country)
        
        self.summonsMessageBody = user.summonsMessageBody
        self.summonsMessageSignature = user.summonsMessageSignature
        self.summonsAvailablePaymentMethods = user.summonsAvailablePaymentMethods
        self.summonsDisplayFormat = user.summonsDisplayFormat
        self.summonsDisplayEntryFee = user.summonsDisplayEntryFee
        self.summonsUseFullCustomMessage = user.summonsUseFullCustomMessage
        self.matchFormatsDefaultDuration = user.matchFormatsDefaultDuration
        self.bracketMatchFormatPreference = user.bracketMatchFormatPreference
        self.groupStageMatchFormatPreference = user.groupStageMatchFormatPreference
        self.loserBracketMatchFormatPreference = user.loserBracketMatchFormatPreference
        
    }
    
    required init(from decoder: Decoder) throws {
        fatalError("init(from:) has not been implemented")
    }
    
    required public init() {
        self.password = ""
        super.init()
    }
    
    public var password: String
    
    private enum CodingKeys: String, CodingKey {
        case password
    }

    override func encode(to encoder: Encoder) throws {
        try super.encode(to: encoder)
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(self.password, forKey: .password)
    }
}
