//
//  Club.swift
//  PadelClub
//
//  Created by Laurent Morvillier on 02/02/2024.
//

import Foundation
import SwiftUI
import LeStorage

@Observable
class Club : ModelObject, Storable, Hashable {
    
    static func resourceName() -> String { return "clubs" }
    static func tokenExemptedMethods() -> [HTTPMethod] { return [.get] }

    static func == (lhs: Club, rhs: Club) -> Bool {
        lhs.id == rhs.id
    }
    
    func hash(into hasher: inout Hasher) {
        return hasher.combine(id)
    }

    var id: String = Store.randomId()
    var creator: String?
    var name: String
    var acronym: String
    var phone: String?
    var code: String?
    //var federalClubData: Data?
    var address: String?
    var city: String?
    var zipCode: String?
    var latitude: Double?
    var longitude: Double?
    var courtCount: Int = 2
    var broadcastCode: String?
//    var alphabeticalName: Bool = false
    
    internal init(creator: String? = nil, name: String, acronym: String? = nil, phone: String? = nil, code: String? = nil, address: String? = nil, city: String? = nil, zipCode: String? = nil, latitude: Double? = nil, longitude: Double? = nil, courtCount: Int = 2, broadcastCode: String? = nil) {
        self.name = name
        self.creator = creator
        self.acronym = acronym ?? name.acronym()
        self.phone = phone
        self.code = code
        self.address = address
        self.city = city
        self.zipCode = zipCode
        self.latitude = latitude
        self.longitude = longitude
        self.courtCount = courtCount
        self.broadcastCode = broadcastCode
    }
    
    override func copyFromServerInstance(_ instance: any Storable) -> Bool {
        guard let copy = instance as? Club else { return false }
        self.broadcastCode = copy.broadcastCode
        Logger.log("write code: \(self.broadcastCode)")
        return true
    }

    func clubTitle(_ displayStyle: DisplayStyle = .wide) -> String {
        switch displayStyle {
        case .wide, .title:
            return name
        case .short:
            return acronym
        }
    }
    
    func shareURL() -> URL? {
        return URL(string: URLs.main.url.appending(path: "?club=\(id)").absoluteString.removingPercentEncoding!)
    }
        
    var customizedCourts: [Court] {
        Store.main.filter { $0.club == self.id }.sorted(by: \.index)
    }

    override func deleteDependencies() throws {
        DataStore.shared.courts.deleteDependencies(self.customizedCourts)
    }
 
    enum CodingKeys: String, CodingKey {
        case _id = "id"
        case _creator = "creator"
        case _name = "name"
        case _acronym = "acronym"
        case _phone = "phone"
        case _code = "code"
        case _address = "address"
        case _city = "city"
        case _zipCode = "zipCode"
        case _latitude = "latitude"
        case _longitude = "longitude"
        case _courtCount = "courtCount"
        case _broadcastCode = "broadcastCode"
//        case _alphabeticalName = "alphabeticalName"
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        
        try container.encode(id, forKey: ._id)
        
        if let creator = creator {
            try container.encode(creator, forKey: ._creator)
        } else {
            try container.encodeNil(forKey: ._creator)
        }
        
        try container.encode(name, forKey: ._name)
        try container.encode(acronym, forKey: ._acronym)
        
        if let phone = phone {
            try container.encode(phone, forKey: ._phone)
        } else {
            try container.encodeNil(forKey: ._phone)
        }
        
        if let code = code {
            try container.encode(code, forKey: ._code)
        } else {
            try container.encodeNil(forKey: ._code)
        }
        
        if let address = address {
            try container.encode(address, forKey: ._address)
        } else {
            try container.encodeNil(forKey: ._address)
        }
        
        if let city = city {
            try container.encode(city, forKey: ._city)
        } else {
            try container.encodeNil(forKey: ._city)
        }
        
        if let zipCode = zipCode {
            try container.encode(zipCode, forKey: ._zipCode)
        } else {
            try container.encodeNil(forKey: ._zipCode)
        }
        
        if let latitude = latitude {
            try container.encode(latitude, forKey: ._latitude)
        } else {
            try container.encodeNil(forKey: ._latitude)
        }
        
        if let longitude = longitude {
            try container.encode(longitude, forKey: ._longitude)
        } else {
            try container.encodeNil(forKey: ._longitude)
        }
        
        try container.encode(courtCount, forKey: ._courtCount)
        
        if let broadcastCode {
            try container.encode(broadcastCode, forKey: ._broadcastCode)
        } else {
            try container.encodeNil(forKey: ._broadcastCode)
        }
        
 //       try container.encode(alphabeticalName, forKey: ._alphabeticalName)
    }

}

extension Club {
    var isValid: Bool {
        name.isEmpty == false && acronym.isEmpty == false
    }
    
    func automaticShortName() -> String {
        name.acronym()
    }
    
    enum AcronymMode: String, CaseIterable {
        case automatic = "Automatique"
        case custom = "Personalisée"
    }
    
    func shortNameMode() -> AcronymMode {
        (acronym.isEmpty || acronym == automaticShortName()) ? .automatic : .custom
    }
    
    func hasTenupId() -> Bool {
        code != nil
    }
    
    func federalLink() -> URL? {
        guard let code else { return nil }
        return URL(string: "https://tenup.fft.fr/club/\(code)")
    }
    
    func courtName(atIndex courtIndex: Int) -> String {
        courtNameIfAvailable(atIndex: courtIndex) ?? Court.courtIndexedTitle(atIndex: courtIndex)
    }
    
    func courtNameIfAvailable(atIndex courtIndex: Int) -> String? {
        customizedCourts.first(where: { $0.index == courtIndex })?.name
    }
    
    func update(fromClub club: Club) {
        self.acronym = club.acronym
        self.name = club.name
        self.phone = club.phone
        self.code = club.code
        self.address = club.address
        self.city = club.city
        self.zipCode = club.zipCode
        self.latitude = club.latitude
        self.longitude = club.longitude
    }
    
    func hasBeenCreated(by creatorId: String?) -> Bool {
        guard let creatorId else { return false }
        guard let creator else { return false }
        return creatorId == creator
    }
    
    func isFavorite() -> Bool {
        return DataStore.shared.user.clubs.contains(where: { $0 == self.id })
    }
    
    static func findOrCreate(name: String, code: String?, city: String? = nil, zipCode: String? = nil) -> Club {
        
        /*
         
         identify a club : code, name, ??
         
         */
        let clubs: [Club] = Store.main.filter(isIncluded: { (code == nil && $0.name == name && $0.city == city && $0.zipCode == zipCode) || code != nil && $0.code == code })

        if clubs.isEmpty == false {
            return clubs.first!
        } else {
            return Club(creator: Store.main.userId, name: name, code: code, city: city, zipCode: zipCode)
        }
    }
    
}
