//
//  DateUtilsTests.swift
//  honeyDueTests
//
//  Unit tests for DateUtils formatting, parsing, and timezone utilities.
//

import Testing
import Foundation
@testable import honeyDue

// MARK: - DateUtils.formatDate Tests

struct DateUtilsFormatDateTests {

    @Test func todayReturnsToday() {
        let today = DateUtils.todayString()
        let result = DateUtils.formatDate(today)
        #expect(result == "Today")
    }

    @Test func nilReturnsEmpty() {
        let result = DateUtils.formatDate(nil)
        #expect(result == "")
    }

    @Test func emptyReturnsEmpty() {
        let result = DateUtils.formatDate("")
        #expect(result == "")
    }

    @Test func invalidDateReturnsSelf() {
        let result = DateUtils.formatDate("not-a-date")
        #expect(result == "not-a-date")
    }

    @Test func dateWithTimePartExtractsDate() {
        let today = DateUtils.todayString()
        let result = DateUtils.formatDate("\(today)T12:00:00Z")
        #expect(result == "Today")
    }
}

// MARK: - DateUtils.formatDateMedium Tests

struct DateUtilsFormatDateMediumTests {

    @Test func validDateFormatsAsMedium() {
        let result = DateUtils.formatDateMedium("2024-01-15")
        #expect(result == "Jan 15, 2024")
    }

    @Test func nilReturnsEmpty() {
        let result = DateUtils.formatDateMedium(nil)
        #expect(result == "")
    }

    @Test func invalidDateReturnsSelf() {
        let result = DateUtils.formatDateMedium("bad-date")
        #expect(result == "bad-date")
    }
}

// MARK: - DateUtils.isOverdue Tests

struct DateUtilsIsOverdueTests {

    @Test func pastDateIsOverdue() {
        let result = DateUtils.isOverdue("2020-01-01")
        #expect(result == true)
    }

    @Test func futureDateIsNotOverdue() {
        let result = DateUtils.isOverdue("2099-12-31")
        #expect(result == false)
    }

    @Test func nilIsNotOverdue() {
        let result = DateUtils.isOverdue(nil)
        #expect(result == false)
    }

    @Test func emptyIsNotOverdue() {
        let result = DateUtils.isOverdue("")
        #expect(result == false)
    }

    @Test func todayIsNotOverdue() {
        let today = DateUtils.todayString()
        let result = DateUtils.isOverdue(today)
        #expect(result == false)
    }
}

// MARK: - DateUtils.parseDate Tests

struct DateUtilsParseDateTests {

    @Test func validDateStringParsed() {
        let date = DateUtils.parseDate("2024-06-15")
        #expect(date != nil)
    }

    @Test func nilReturnsNil() {
        let date = DateUtils.parseDate(nil)
        #expect(date == nil)
    }

    @Test func emptyReturnsNil() {
        let date = DateUtils.parseDate("")
        #expect(date == nil)
    }

    @Test func invalidReturnsNil() {
        let date = DateUtils.parseDate("not-a-date")
        #expect(date == nil)
    }

    @Test func dateTimeStringExtractsDate() {
        let date = DateUtils.parseDate("2024-06-15T10:30:00Z")
        #expect(date != nil)
    }
}

// MARK: - DateUtils.formatHour Tests

struct DateUtilsFormatHourTests {

    @Test func midnightFormatsCorrectly() {
        #expect(DateUtils.formatHour(0) == "12:00 AM")
    }

    @Test func morningFormatsCorrectly() {
        #expect(DateUtils.formatHour(8) == "8:00 AM")
    }

    @Test func noonFormatsCorrectly() {
        #expect(DateUtils.formatHour(12) == "12:00 PM")
    }

    @Test func afternoonFormatsCorrectly() {
        #expect(DateUtils.formatHour(14) == "2:00 PM")
    }

    @Test func elevenPMFormatsCorrectly() {
        #expect(DateUtils.formatHour(23) == "11:00 PM")
    }

    @Test func oneAMFormatsCorrectly() {
        #expect(DateUtils.formatHour(1) == "1:00 AM")
    }

    @Test func elevenAMFormatsCorrectly() {
        #expect(DateUtils.formatHour(11) == "11:00 AM")
    }

    @Test func onePMFormatsCorrectly() {
        #expect(DateUtils.formatHour(13) == "1:00 PM")
    }
}

// MARK: - DateUtils.formatRelativeDate Tests

struct DateUtilsFormatRelativeDateTests {

    @Test func nilReturnsEmpty() {
        let result = DateUtils.formatRelativeDate(nil)
        #expect(result == "")
    }

    @Test func emptyReturnsEmpty() {
        let result = DateUtils.formatRelativeDate("")
        #expect(result == "")
    }

    @Test func todayReturnsToday() {
        let today = DateUtils.todayString()
        let result = DateUtils.formatRelativeDate(today)
        #expect(result == "Today")
    }

    @Test func invalidReturnsSelf() {
        let result = DateUtils.formatRelativeDate("bad")
        #expect(result == "bad")
    }
}

// MARK: - DateUtils.localHourToUtc / utcHourToLocal Round-Trip Tests

struct TimezoneConversionTests {

    @Test func roundTripLocalToUtcToLocal() {
        let localHour = 10
        let utc = DateUtils.localHourToUtc(localHour)
        let backToLocal = DateUtils.utcHourToLocal(utc)
        #expect(backToLocal == localHour)
    }

    @Test func utcAndLocalDifferByTimezoneOffset() {
        // Just verify it returns a value in 0-23 range
        let utc = DateUtils.localHourToUtc(15)
        #expect(utc >= 0 && utc <= 23)
    }
}

// MARK: - DateExtensions Tests

struct DateExtensionsTests {

    @Test func todayIsToday() {
        #expect(Date().isToday)
    }

    @Test func todayRelativeDescriptionIsToday() {
        #expect(Date().relativeDescription == "Today")
    }

    @Test func apiFormatHasCorrectPattern() {
        let formatted = Date().formattedAPI()
        // Should match yyyy-MM-dd pattern
        let parts = formatted.split(separator: "-")
        #expect(parts.count == 3)
        #expect(parts[0].count == 4)
        #expect(parts[1].count == 2)
        #expect(parts[2].count == 2)
    }

    @Test func distantPastIsPast() {
        let past = Date.distantPast
        #expect(past.isPast)
    }

    @Test func distantFutureIsNotPast() {
        let future = Date.distantFuture
        #expect(!future.isPast)
    }
}

// MARK: - String Date Extension Tests

struct StringDateExtensionTests {

    @Test func validAPIDateParsed() {
        let date = "2024-06-15".toDate()
        #expect(date != nil)
    }

    @Test func invalidDateReturnsNil() {
        let date = "invalid".toDate()
        #expect(date == nil)
    }

    @Test func dateTimeStringParsed() {
        let date = "2024-06-15T10:30:00Z".toDate()
        #expect(date != nil)
    }

    @Test func pastDateIsOverdue() {
        #expect("2020-01-01".isOverdue())
    }

    @Test func futureDateIsNotOverdue() {
        #expect(!"2099-12-31".isOverdue())
    }

    @Test func toFormattedDateReturnsFormatted() {
        let result = "2024-01-15".toFormattedDate()
        #expect(result == "Jan 15, 2024")
    }

    @Test func invalidDateToFormattedReturnsSelf() {
        let result = "bad-date".toFormattedDate()
        #expect(result == "bad-date")
    }
}

// MARK: - Helper for date tests

private extension DateUtils {
    /// Returns today's date as an API-formatted string (yyyy-MM-dd)
    static func todayString() -> String {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd"
        return formatter.string(from: Date())
    }
}
