//
//  ReviewRequestManager.swift
//  Reflect
//
//  Manages in-app review requests using StoreKit.
//  Follows Apple's guidelines: requests at moments of delight,
//  limits frequency, and never interrupts critical flows.
//

import Foundation
import StoreKit

@MainActor
final class ReviewRequestManager {
    static let shared = ReviewRequestManager()

    // MARK: - Configuration

    /// Minimum mood entries before first review request
    private let minimumEntriesForReview = 5

    /// Minimum days between review requests
    private let minimumDaysBetweenRequests = 14

    /// Streak milestones that trigger review consideration
    private let streakMilestones: Set<Int> = [3, 7, 14, 30, 50, 100]

    // MARK: - UserDefaults Keys

    private enum Keys: String {
        case lastReviewRequestDate = "reflect_lastReviewRequestDate"
        case totalReviewRequests = "reflect_totalReviewRequests"
        case totalMoodEntriesLogged = "reflect_totalMoodEntriesLogged"
        case lastReviewRequestVersion = "reflect_lastReviewRequestVersion"
    }

    private init() {}

    // MARK: - Public API

    /// Call after a successful mood entry to potentially request a review.
    /// The manager decides internally whether conditions are met.
    func onMoodLogged(streak: Int) {
        incrementEntryCount()

        guard shouldRequestReview(streak: streak) else { return }

        requestReview()
    }

    /// Force a review request check (e.g., after completing onboarding).
    /// Still respects frequency limits.
    func checkForReviewOpportunity() {
        guard hasMetMinimumUsage() && hasEnoughTimePassed() else { return }
        requestReview()
    }

    // MARK: - Private Logic

    private func shouldRequestReview(streak: Int) -> Bool {
        // Must have minimum entries
        guard hasMetMinimumUsage() else { return false }

        // Must have enough time since last request
        guard hasEnoughTimePassed() else { return false }

        // Check if this is a "moment of delight"
        guard isMomentOfDelight(streak: streak) else { return false }

        return true
    }

    private func hasMetMinimumUsage() -> Bool {
        let totalEntries = UserDefaults.standard.integer(forKey: Keys.totalMoodEntriesLogged.rawValue)
        return totalEntries >= minimumEntriesForReview
    }

    private func hasEnoughTimePassed() -> Bool {
        guard let lastRequest = UserDefaults.standard.object(forKey: Keys.lastReviewRequestDate.rawValue) as? Date else {
            // Never requested before
            return true
        }

        let daysSinceLastRequest = Calendar.current.dateComponents([.day], from: lastRequest, to: Date()).day ?? 0
        return daysSinceLastRequest >= minimumDaysBetweenRequests
    }

    private func isMomentOfDelight(streak: Int) -> Bool {
        // Streak milestones are moments of delight
        if streakMilestones.contains(streak) {
            return true
        }

        // Every 10th entry after the first 5 is also a good moment
        let totalEntries = UserDefaults.standard.integer(forKey: Keys.totalMoodEntriesLogged.rawValue)
        if totalEntries >= minimumEntriesForReview && totalEntries % 10 == 0 {
            return true
        }

        return false
    }

    private func incrementEntryCount() {
        let current = UserDefaults.standard.integer(forKey: Keys.totalMoodEntriesLogged.rawValue)
        UserDefaults.standard.set(current + 1, forKey: Keys.totalMoodEntriesLogged.rawValue)
    }

    private func requestReview() {
        // Get the current window scene
        guard let windowScene = UIApplication.shared.connectedScenes
            .compactMap({ $0 as? UIWindowScene })
            .first(where: { $0.activationState == .foregroundActive }) else {
            return
        }

        // Record that we're requesting
        UserDefaults.standard.set(Date(), forKey: Keys.lastReviewRequestDate.rawValue)

        let totalRequests = UserDefaults.standard.integer(forKey: Keys.totalReviewRequests.rawValue)
        UserDefaults.standard.set(totalRequests + 1, forKey: Keys.totalReviewRequests.rawValue)

        // Store current app version
        if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
            UserDefaults.standard.set(version, forKey: Keys.lastReviewRequestVersion.rawValue)
        }

        // Request the review - iOS decides whether to actually show it
        AppStore.requestReview(in: windowScene)
    }

    // MARK: - Debug / Testing

    #if DEBUG
    func resetForTesting() {
        UserDefaults.standard.removeObject(forKey: Keys.lastReviewRequestDate.rawValue)
        UserDefaults.standard.removeObject(forKey: Keys.totalReviewRequests.rawValue)
        UserDefaults.standard.removeObject(forKey: Keys.totalMoodEntriesLogged.rawValue)
        UserDefaults.standard.removeObject(forKey: Keys.lastReviewRequestVersion.rawValue)
    }

    var debugInfo: String {
        let entries = UserDefaults.standard.integer(forKey: Keys.totalMoodEntriesLogged.rawValue)
        let requests = UserDefaults.standard.integer(forKey: Keys.totalReviewRequests.rawValue)
        let lastDate = UserDefaults.standard.object(forKey: Keys.lastReviewRequestDate.rawValue) as? Date
        return "Entries: \(entries), Requests: \(requests), Last: \(lastDate?.description ?? "never")"
    }
    #endif
}
