//
//  BackupServiceTests.swift
//  oAITests
//
// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
// Copyright (C) 2026 Rune Olsen

import Testing
import Foundation
@testable import Confab

@Suite("BackupService.decideFavoritesSync")
struct BackupServiceFavoritesSyncTests {

    private let now = Date(timeIntervalSince1970: 1_700_000_000)

    @Test("No remote copy yet -- push local state")
    func noRemoteCopy() {
        let decision = BackupService.decideFavoritesSync(localIds: ["a", "b"], localUpdatedAt: "", remote: nil, now: now)
        #expect(decision == .pushLocal)
    }

    @Test("Remote is newer -- apply it locally")
    func remoteNewer() {
        let remote = FavoritesPayload(updatedAt: "2026-02-01T00:00:00Z", ids: ["x", "y"])
        let decision = BackupService.decideFavoritesSync(
            localIds: ["a"],
            localUpdatedAt: "2026-01-01T00:00:00Z",
            remote: remote,
            now: now
        )
        #expect(decision == .applyRemote(ids: ["x", "y"], updatedAt: "2026-02-01T00:00:00Z"))
    }

    @Test("Local is newer -- push local state, don't touch remote")
    func localNewer() {
        let remote = FavoritesPayload(updatedAt: "2026-01-01T00:00:00Z", ids: ["x"])
        let decision = BackupService.decideFavoritesSync(
            localIds: ["a"],
            localUpdatedAt: "2026-02-01T00:00:00Z",
            remote: remote,
            now: now
        )
        #expect(decision == .pushLocal)
    }

    @Test("Tied timestamps with different sets -- merge via union and push")
    func tiedTimestampsDifferentSets() {
        let remote = FavoritesPayload(updatedAt: "", ids: ["b", "c"])
        let decision = BackupService.decideFavoritesSync(localIds: ["a", "b"], localUpdatedAt: "", remote: remote, now: now)
        guard case .mergeAndPush(let ids, let updatedAt) = decision else {
            Issue.record("Expected .mergeAndPush")
            return
        }
        #expect(ids == ["a", "b", "c"])
        #expect(!updatedAt.isEmpty) // stamped with `now`, not left blank
    }

    @Test("Tied timestamps with identical sets -- no-op, already in sync")
    func tiedTimestampsIdenticalSets() {
        let remote = FavoritesPayload(updatedAt: "2026-01-01T00:00:00Z", ids: ["a", "b"])
        let decision = BackupService.decideFavoritesSync(
            localIds: ["a", "b"],
            localUpdatedAt: "2026-01-01T00:00:00Z",
            remote: remote,
            now: now
        )
        #expect(decision == .noop)
    }
}

@Suite("BackupService.isBackupDue")
struct BackupServiceAutoBackupTests {

    private let now = Date(timeIntervalSince1970: 1_700_000_000)
    private let oneHour: TimeInterval = 3600

    @Test("Manual frequency is never due")
    func manualNeverDue() {
        #expect(!BackupService.isBackupDue(frequency: "manual", lastBackupDate: nil, now: now))
        #expect(!BackupService.isBackupDue(frequency: "manual", lastBackupDate: now.addingTimeInterval(-1_000_000), now: now))
    }

    @Test("No prior backup at all is always due, regardless of frequency")
    func noPriorBackupIsAlwaysDue() {
        #expect(BackupService.isBackupDue(frequency: "daily", lastBackupDate: nil, now: now))
        #expect(BackupService.isBackupDue(frequency: "weekly", lastBackupDate: nil, now: now))
    }

    @Test("Daily: not due before 24 hours have passed, due at or after")
    func dailyThreshold() {
        let justUnder = now.addingTimeInterval(-(24 * oneHour - 1))
        let exactly = now.addingTimeInterval(-(24 * oneHour))
        #expect(!BackupService.isBackupDue(frequency: "daily", lastBackupDate: justUnder, now: now))
        #expect(BackupService.isBackupDue(frequency: "daily", lastBackupDate: exactly, now: now))
    }

    @Test("Weekly: not due before 7 days have passed, due at or after")
    func weeklyThreshold() {
        let justUnder = now.addingTimeInterval(-(7 * 24 * oneHour - 1))
        let exactly = now.addingTimeInterval(-(7 * 24 * oneHour))
        #expect(!BackupService.isBackupDue(frequency: "weekly", lastBackupDate: justUnder, now: now))
        #expect(BackupService.isBackupDue(frequency: "weekly", lastBackupDate: exactly, now: now))
    }
}
