// // Event_v2.swift // Padel Tournament // // Created by razmig on 10/03/2024. // import Foundation import LeStorage import SwiftUI @Observable final public class Event: BaseEvent { public init(creator: String? = nil, club: String? = nil, name: String? = nil, tenupId: String? = nil) { super.init(creator: creator, club: club, name: name, tenupId: tenupId) self.relatedUser = creator } required init(from decoder: Decoder) throws { try super.init(from: decoder) } required public init() { super.init() } public override func deleteDependencies(store: Store, shouldBeSynchronized: Bool) { store.deleteDependencies(type: Tournament.self, shouldBeSynchronized: shouldBeSynchronized) { $0.event == self.id && $0.isDeleted == false } store.deleteDependencies(type: DateInterval.self, shouldBeSynchronized: shouldBeSynchronized) { $0.event == self.id } // let tournaments = self.tournaments // for tournament in tournaments { // tournament.deleteDependencies(store: store, shouldBeSynchronized: shouldBeSynchronized) // } // // DataStore.shared.tournaments.deleteDependencies(tournaments, shouldBeSynchronized: shouldBeSynchronized) // // let courtsUnavailabilities = self.courtsUnavailability // for courtsUnavailability in courtsUnavailabilities { // courtsUnavailability.deleteDependencies(store: store, shouldBeSynchronized: shouldBeSynchronized) // } // DataStore.shared.dateIntervals.deleteDependencies(courtsUnavailabilities, shouldBeSynchronized: shouldBeSynchronized) } // MARK: - Computed dependencies public var tournaments: [Tournament] { DataStore.shared.tournaments.filter { $0.event == self.id && $0.isDeleted == false }.sorted(by: \.startDate) } public func clubObject() -> Club? { guard let club else { return nil } return Store.main.findById(club) } public var courtsUnavailability: [DateInterval] { DataStore.shared.dateIntervals.filter({ $0.event == id }) } // MARK: - public func eventCourtCount() -> Int { tournaments.map { $0.courtCount }.max() ?? 2 } public func eventStartDate() -> Date { tournaments.map { $0.startDate }.min() ?? Date() } public func eventDayDuration() -> Int { tournaments.map { $0.dayDuration }.max() ?? 1 } public func eventTitle() -> String { if let name, name.isEmpty == false { return name } else { return "Événement" } } public func existingBuild(_ build: any TournamentBuildHolder) -> Tournament? { tournaments.first(where: { $0.isSameBuild(build) }) } public func tournamentsCourtsUsed(exluding tournamentId: String) -> [DateInterval] { tournaments.filter { $0.id != tournamentId }.flatMap({ tournament in tournament.getPlayedMatchDateIntervals(in: self) }) } public func federalTournaments() -> [Tournament] { tournaments.filter({ $0.isAnimation() == false && $0.isCanceled == false && $0.isDeleted == false }) } public func paidTournaments() -> [Tournament] { tournaments.filter({ $0.isFree() == false && $0.isCanceled == false && $0.isDeleted == false }) } public func confirmedTournaments() -> [Tournament] { tournaments.filter({ $0.isCanceled == false && $0.isDeleted == false }) } public func shareURL() -> URL? { return URL(string: URLs.main.url.appending(path: "event/\(id)").absoluteString.removingPercentEncoding!) } public func formattedDateInterval() -> String { let tournaments = self.tournaments guard !tournaments.isEmpty else { return "" // Handle empty tournament list } let firstTournament = tournaments.first! let lastTournament = tournaments.last! // Helper to check if two dates are on the same day func isSameDay(date1: Date, date2: Date) -> Bool { return Calendar.current.isDate(date1, inSameDayAs: date2) } // Scenario 1: Only one tournament if tournaments.count == 1 { return firstTournament.startDate.formattedAsDate() } // Scenario 2: Multiple tournaments, but all start and end on the same day (single-day event overall) let overallEventIsSingleDay = isSameDay(date1: firstTournament.startDate, date2: lastTournament.startDate) if overallEventIsSingleDay { return firstTournament.startDate.formattedAsDate() } // Scenario 3: Multiple tournaments, spanning multiple days (requires "Du ... au ...") let startDay = firstTournament.startDate.localizedDay() let endDay = lastTournament.startDate.localizedDay() let startMonthYear = firstTournament.startDate.monthYearFormatted let endMonthYear = lastTournament.startDate.monthYearFormatted let calendar = Calendar.current let firstStartComponents = calendar.dateComponents([.year, .month], from: firstTournament.startDate) let lastEndComponents = calendar.dateComponents([.year, .month], from: lastTournament.startDate) if firstStartComponents.year == lastEndComponents.year && firstStartComponents.month == lastEndComponents.month { // Same month and year: "Du 13 au 15 Juin 2025" return "Du \(startDay) au \(endDay) \(startMonthYear)" } else if firstStartComponents.year == lastEndComponents.year { // Different months, same year: "Du 13 Juin au 15 Juillet 2025" return "Du \(startDay) \(startMonthYear) au \(endDay) \(endMonthYear)" } else { // Different years: "Du 13 Juin 2025 au 15 Juin 2026" return "Du \(startDay) \(startMonthYear) au \(endDay) \(endMonthYear)" } } public func tournamentInformation() -> String? { confirmedTournaments().first?.information } public func eventLinksPasteData() -> String { let tournaments = self.confirmedTournaments() var link = [String?]() link.append(eventTitle()) link.append(tournamentInformation()) if let url = shareURL() { var tournamentLink = [String]() tournamentLink.append("Lien de l'événement") tournamentLink.append(url.absoluteString) let eventLink = tournamentLink.joined(separator: "\n") link.append(eventLink) } link.append("Retrouvez toutes les infos en suivant le\(tournaments.count.pluralSuffix) lien\(tournaments.count.pluralSuffix) ci-dessous :") link.append(tournaments.compactMap({ tournament in if let url = tournament.shareURL(.info) { var tournamentLink = [String]() tournamentLink.append(tournament.tournamentTitle(.title)) tournamentLink.append(url.absoluteString) return tournamentLink.joined(separator: "\n") } else { return nil } }).joined(separator: "\n\n")) return link.compactMap({ $0 }).joined(separator: "\n\n") } func insertOnServer() throws { DataStore.shared.events.writeChangeAndInsertOnServer(instance: self) for tournament in self.tournaments { try tournament.insertOnServer() } for dataInterval in self.courtsUnavailability { try dataInterval.insertOnServer() } } }