import Foundation
import XCTest
@testable import AlignerCore

final class EntitlementPolicyTests: XCTestCase {
    private let now = Date(timeIntervalSince1970: 1_800_000_000)

    func testTrialIsAllowedBeforeThirtyDayBoundary() {
        let startedAt = now.addingTimeInterval(-29 * 24 * 60 * 60 - 23 * 60 * 60 - 59 * 60)
        let snapshot = EntitlementSnapshot(
            trialState: EntitlementPolicy.trialStarted(at: startedAt),
            licenseState: .none,
            validationFreshness: .neverChecked
        )

        XCTAssertEqual(
            EntitlementPolicy.evaluate(snapshot: snapshot, feature: .windowShortcutActivation, now: now),
            .proAllowed(reason: .trialActive)
        )
    }

    func testTrialExpiresAtThirtyDayBoundary() {
        let startedAt = now.addingTimeInterval(-EntitlementPolicy.defaultTrialDuration)
        let snapshot = EntitlementSnapshot(
            trialState: EntitlementPolicy.trialStarted(at: startedAt),
            licenseState: .none,
            validationFreshness: .neverChecked
        )

        XCTAssertEqual(
            EntitlementPolicy.evaluate(snapshot: snapshot, feature: .windowShortcutActivation, now: now),
            .proDenied(reason: .trialExpired)
        )
    }

    func testInvalidTrialRecordIsDeniedWhenNoLicenseExists() {
        let snapshot = EntitlementSnapshot(
            trialState: .active(startedAt: now, expiresAt: now.addingTimeInterval(-1)),
            licenseState: .none,
            validationFreshness: .neverChecked
        )

        XCTAssertEqual(
            EntitlementPolicy.evaluate(snapshot: snapshot, feature: .windowShortcutActivation, now: now),
            .proDenied(reason: .invalidLocalRecord)
        )
    }

    func testValidLicenseAllowsProAfterTrialExpired() {
        let snapshot = EntitlementSnapshot(
            trialState: expiredTrial(),
            licenseState: activeLicense(),
            validationFreshness: .valid(
                lastValidAt: now.addingTimeInterval(-60),
                nextCheckAt: now.addingTimeInterval(60)
            )
        )

        XCTAssertEqual(
            EntitlementPolicy.evaluate(snapshot: snapshot, feature: .windowShortcutActivation, now: now),
            .proAllowed(reason: .licenseValid)
        )
    }

    func testOfflineGraceAllowsProBeforeFourteenDayBoundary() {
        let lastAttemptAt = now.addingTimeInterval(-13 * 24 * 60 * 60 - 23 * 60 * 60 - 59 * 60)
        let snapshot = EntitlementSnapshot(
            trialState: expiredTrial(),
            licenseState: activeLicense(),
            validationFreshness: EntitlementPolicy.offlineGrace(lastAttemptAt: lastAttemptAt)
        )

        XCTAssertEqual(
            EntitlementPolicy.evaluate(snapshot: snapshot, feature: .windowShortcutActivation, now: now),
            .proAllowed(reason: .offlineGrace)
        )
    }

    func testOfflineGraceExpiresAtFourteenDayBoundary() {
        let lastAttemptAt = now.addingTimeInterval(-EntitlementPolicy.defaultOfflineGraceDuration)
        let snapshot = EntitlementSnapshot(
            trialState: expiredTrial(),
            licenseState: activeLicense(),
            validationFreshness: EntitlementPolicy.offlineGrace(lastAttemptAt: lastAttemptAt)
        )

        XCTAssertEqual(
            EntitlementPolicy.evaluate(snapshot: snapshot, feature: .windowShortcutActivation, now: now),
            .proDenied(reason: .graceExpired)
        )
    }

    func testHardFailureIsDeniedWhenTrialIsExpired() {
        let snapshot = EntitlementSnapshot(
            trialState: expiredTrial(),
            licenseState: activeLicense(),
            validationFreshness: .hardFailure(reason: .revoked)
        )

        XCTAssertEqual(
            EntitlementPolicy.evaluate(snapshot: snapshot, feature: .windowShortcutActivation, now: now),
            .proDenied(reason: .hardFailure)
        )
    }

    func testActiveTrialStillAllowsWhenLicenseVerificationFails() {
        let snapshot = EntitlementSnapshot(
            trialState: EntitlementPolicy.trialStarted(at: now.addingTimeInterval(-60)),
            licenseState: activeLicense(),
            validationFreshness: .hardFailure(reason: .serverRejected)
        )

        XCTAssertEqual(
            EntitlementPolicy.evaluate(snapshot: snapshot, feature: .windowShortcutActivation, now: now),
            .proAllowed(reason: .trialActive)
        )
    }

    func testDeactivatedLicenseIsDeniedAfterTrialExpired() {
        let snapshot = EntitlementSnapshot(
            trialState: expiredTrial(),
            licenseState: .deactivatedLocal,
            validationFreshness: .neverChecked
        )

        XCTAssertEqual(
            EntitlementPolicy.evaluate(snapshot: snapshot, feature: .windowShortcutActivation, now: now),
            .proDenied(reason: .licenseDeactivated)
        )
    }

    func testDisabledLicenseIsDeniedAfterTrialExpired() {
        let snapshot = EntitlementSnapshot(
            trialState: expiredTrial(),
            licenseState: .activated(fingerprint: "abc123", instanceID: "instance-1", status: .disabled),
            validationFreshness: .valid(
                lastValidAt: now.addingTimeInterval(-60),
                nextCheckAt: now.addingTimeInterval(60)
            )
        )

        XCTAssertEqual(
            EntitlementPolicy.evaluate(snapshot: snapshot, feature: .windowShortcutActivation, now: now),
            .proDenied(reason: .licenseDisabled)
        )
    }

    func testProductMismatchIsDeniedAfterTrialExpired() {
        let snapshot = EntitlementSnapshot(
            trialState: expiredTrial(),
            licenseState: .mismatch(reason: .product),
            validationFreshness: .neverChecked
        )

        XCTAssertEqual(
            EntitlementPolicy.evaluate(snapshot: snapshot, feature: .windowShortcutActivation, now: now),
            .proDenied(reason: .licenseMismatch)
        )
    }

    func testRemoteRevokedLicenseIsDeniedAfterTrialExpired() {
        let snapshot = EntitlementSnapshot(
            trialState: expiredTrial(),
            licenseState: .revokedOrExpiredRemote(reason: .revoked),
            validationFreshness: .neverChecked
        )

        XCTAssertEqual(
            EntitlementPolicy.evaluate(snapshot: snapshot, feature: .windowShortcutActivation, now: now),
            .proDenied(reason: .licenseRevokedOrExpired)
        )
    }

    func testFixtureProviderCoversRound015NamedStates() {
        let expectations: [EntitlementFixtureState: EffectiveEntitlement] = [
            .trialActive: .proAllowed(reason: .trialActive),
            .trialExpired: .proDenied(reason: .trialExpired),
            .proUnlocked: .proAllowed(reason: .licenseValid),
            .offlineGrace: .proAllowed(reason: .offlineGrace),
            .verifyFailed: .proDenied(reason: .hardFailure)
        ]

        for (fixtureState, expectedEntitlement) in expectations {
            let provider = FixtureEntitlementProvider(fixtureState: fixtureState, now: now)
            XCTAssertEqual(
                provider.entitlement(for: .windowShortcutActivation, at: now),
                expectedEntitlement,
                "fixture state \(fixtureState.rawValue)"
            )
        }
    }

    private func activeLicense() -> LicenseState {
        .activated(fingerprint: "abc123", instanceID: "instance-1", status: .active)
    }

    private func expiredTrial() -> TrialState {
        .expired(
            startedAt: now.addingTimeInterval(-31 * 24 * 60 * 60),
            expiredAt: now.addingTimeInterval(-24 * 60 * 60)
        )
    }
}
