//
//  Date+Extensions.swift
//  PadelClub
//
//  Created by Razmig Sarkissian on 01/03/2024.
//

import Foundation
enum TimeOfDay {
    case morning
    case noon
    case afternoon
    case evening
    case night
    
    var hello: String {
        switch self {
        case .morning, .noon, .afternoon:
            return "Bonjour"
        case .evening, .night:
            return "Bonsoir"
        }
    }
    
    var goodbye: String {
        switch self {
        case .morning, .noon, .afternoon:
            return "Bonne journée"
        case .evening, .night:
            return "Bonne soirée"
        }
    }

}



extension Date {
    func localizedDate() -> String {
        self.formatted(.dateTime.weekday().day().month()) + " à " + self.formattedAsHourMinute()
    }
    
    func formattedAsHourMinute() -> String {
        formatted(.dateTime.hour().minute())
    }
    
    func formattedAsDate() -> String {
        formatted(.dateTime.weekday().day(.twoDigits).month().year())
    }
    
    var monthYearFormatted: String {
        formatted(.dateTime.month(.wide).year(.defaultDigits))
    }
    
    var twoDigitsYearFormatted: String {
        formatted(Date.FormatStyle(date: .numeric, time: .omitted).locale(Locale(identifier: "fr_FR")).year(.twoDigits))
    }
    
    var timeOfDay: TimeOfDay {
        let hour = Calendar.current.component(.hour, from: self)
        switch hour {
        case 6..<12 : return .morning
        case 12 : return .noon
        case 13..<17 : return .afternoon
        case 17..<22 : return .evening
        default: return .night
        }
    }

}

extension Date {
    func isInCurrentYear() -> Bool {
        let calendar = Calendar.current
        let currentYear = calendar.component(.year, from: Date())
        let yearOfDate = calendar.component(.year, from: self)
        
        return currentYear == yearOfDate
    }
    
    func get(_ components: Calendar.Component..., calendar: Calendar = Calendar.current) -> DateComponents {
        return calendar.dateComponents(Set(components), from: self)
    }
    
    func get(_ component: Calendar.Component, calendar: Calendar = Calendar.current) -> Int {
        return calendar.component(component, from: self)
    }
    
    var tomorrowAtNine: Date {
        let currentHour = Calendar.current.component(.hour, from: self)
        let startOfDay = Calendar.current.startOfDay(for: self)
        if currentHour < 8 {
            return Calendar.current.date(byAdding: .hour, value: 9, to: startOfDay)!
        } else {
            let date = Calendar.current.date(byAdding: .day, value: 1, to: startOfDay)
            return Calendar.current.date(byAdding: .hour, value: 9, to: date!)!
        }
    }
    
    func atBeginningOfDay(hourInt: Int = 9) -> Date {
        Calendar.current.date(byAdding: .hour, value: hourInt, to: self.startOfDay)!
    }
    
    static var firstDayOfWeek = Calendar.current.firstWeekday
    static var capitalizedFirstLettersOfWeekdays: [String] {
        let calendar = Calendar.current
        //           let weekdays = calendar.shortWeekdaySymbols
        
        //           return weekdays.map { weekday in
        //               guard let firstLetter = weekday.first else { return "" }
        //               return String(firstLetter).capitalized
        //           }
        // Adjusted for the different weekday starts
        var weekdays = calendar.veryShortStandaloneWeekdaySymbols
        if firstDayOfWeek > 1 {
            for _ in 1..<firstDayOfWeek {
                if let first = weekdays.first {
                    weekdays.append(first)
                    weekdays.removeFirst()
                }
            }
        }
        return weekdays.map { $0.capitalized }
    }
    
    static var fullMonthNames: [String] {
        let dateFormatter = DateFormatter()
        dateFormatter.locale = Locale.current
        
        return (1...12).compactMap { month in
            dateFormatter.setLocalizedDateFormatFromTemplate("MMMM")
            let date = Calendar.current.date(from: DateComponents(year: 2000, month: month, day: 1))
            return date.map { dateFormatter.string(from: $0) }
        }
    }
    
    var startOfMonth: Date {
        Calendar.current.dateInterval(of: .month, for: self)!.start
    }
    
    var endOfMonth: Date {
        let lastDay = Calendar.current.dateInterval(of: .month, for: self)!.end
        return Calendar.current.date(byAdding: .day, value: -1, to: lastDay)!
    }
    
    var startOfPreviousMonth: Date {
        let dayInPreviousMonth = Calendar.current.date(byAdding: .month, value: -1, to: self)!
        return dayInPreviousMonth.startOfMonth
    }
    
    var numberOfDaysInMonth: Int {
        Calendar.current.component(.day, from: endOfMonth)
    }
    
    //    var sundayBeforeStart: Date {
    //        let startOfMonthWeekday = Calendar.current.component(.weekday, from: startOfMonth)
    //        let numberFromPreviousMonth = startOfMonthWeekday - 1
    //        return Calendar.current.date(byAdding: .day, value: -numberFromPreviousMonth, to: startOfMonth)!
    //    }
    // New to accomodate for different start of week days
    var firstWeekDayBeforeStart: Date {
        let startOfMonthWeekday = Calendar.current.component(.weekday, from: startOfMonth)
        let numberFromPreviousMonth = startOfMonthWeekday - Self.firstDayOfWeek
        return Calendar.current.date(byAdding: .day, value: -numberFromPreviousMonth, to: startOfMonth)!
    }
    
    var calendarDisplayDays: [Date] {
        var days: [Date] = []
        // Current month days
        for dayOffset in 0..<numberOfDaysInMonth {
            let newDay = Calendar.current.date(byAdding: .day, value: dayOffset, to: startOfMonth)
            days.append(newDay!)
        }
        // previous month days
        for dayOffset in 0..<startOfPreviousMonth.numberOfDaysInMonth {
            let newDay = Calendar.current.date(byAdding: .day, value: dayOffset, to: startOfPreviousMonth)
            days.append(newDay!)
        }
        
        // Fixed to accomodate different weekday starts
        return days.filter { $0 >= firstWeekDayBeforeStart && $0 <= endOfMonth }.sorted(by: <)
    }
    
    var monthInt: Int {
        Calendar.current.component(.month, from: self)
    }
    
    var yearInt: Int {
        Calendar.current.component(.year, from: self)
    }
    
    var dayInt: Int {
        Calendar.current.component(.day, from: self)
    }
    
    var startOfDay: Date {
        Calendar.current.startOfDay(for: self)
    }
    
    func endOfDay() -> Date {
        let calendar = Calendar.current
        return calendar.date(bySettingHour: 23, minute: 59, second: 59, of: self)!
    }
    
    func atNine() -> Date {
        let calendar = Calendar.current
        return calendar.date(bySettingHour: 9, minute: 0, second: 0, of: self)!
    }
    
    func atEightAM() -> Date {
        let calendar = Calendar.current
        return calendar.date(bySettingHour: 8, minute: 0, second: 0, of: self)!
    }
}

extension Date {
    func isEarlierThan(_ date: Date) -> Bool {
        self < date
    }
}

extension Date {
    func localizedTime() -> String {
        self.formattedAsHourMinute()
    }

    func localizedDay() -> String {
        self.formatted(.dateTime.weekday(.wide).day())
    }
}
