import Foundation
import ComposeApp

/// Backs the First-Task onboarding screen. Owns the network calls for
/// personalised suggestions and the full template catalog, plus the bulk
/// task-create submission. No hardcoded suggestion rules or fallback
/// catalog — when the API fails the screen shows error+retry+skip.
///
/// Mirrors the Android `OnboardingViewModel.suggestionsState` /
/// `templatesGroupedState` / `createTasksState` flows in a purely Swift
/// shape: calling `APILayer.shared.*` directly is more idiomatic here than
/// observing Kotlin StateFlows, and matches the pattern used by
/// `TaskViewModel.swift`.
@MainActor
final class OnboardingTasksViewModel: ObservableObject {

    // MARK: - Suggestions (For You tab)
    @Published private(set) var suggestions: [TaskSuggestionResponse] = []
    @Published private(set) var profileCompleteness: Double = 0
    @Published private(set) var isLoadingSuggestions = false
    @Published private(set) var suggestionsError: String?
    /// True once `loadSuggestions` has returned any terminal state.
    /// Used by the view to distinguish "haven't tried yet" from "tried and
    /// returned empty".
    @Published private(set) var suggestionsAttempted = false

    // MARK: - Grouped catalog (Browse All tab)
    @Published private(set) var grouped: TaskTemplatesGroupedResponse?
    @Published private(set) var isLoadingGrouped = false
    @Published private(set) var groupedError: String?

    // MARK: - Submission
    @Published private(set) var isSubmitting = false
    @Published private(set) var submitError: String?

    // MARK: - Private Properties
    private let dataManager: DataManagerObservable

    // MARK: - Initialization
    ///
    /// - Parameters:
    ///   - dataManager: Observable cache the VM subscribes to. Defaults
    ///     to the shared singleton.
    ///   - initialSuggestions: Pre-seeded suggestions list. Used by
    ///     snapshot tests/previews so the "For You" tab renders
    ///     populated on first composition, bypassing the
    ///     `loadSuggestions` → APILayer round-trip that fails
    ///     hermetically.
    ///   - initialGrouped: Pre-seeded grouped-templates response. Same
    ///     rationale for the "Browse All" tab.
    init(
        dataManager: DataManagerObservable = .shared,
        initialSuggestions: [TaskSuggestionResponse] = [],
        initialGrouped: TaskTemplatesGroupedResponse? = nil
    ) {
        self.dataManager = dataManager
        self.suggestions = initialSuggestions
        self.grouped = initialGrouped
        // Mark suggestions as "attempted" when any pre-seed data landed
        // so the view's empty-state branch renders instead of the
        // "haven't tried yet" spinner — otherwise the Browse-All tab's
        // seeded `grouped` data would be masked by the suggestions
        // loading placeholder.
        self.suggestionsAttempted = !initialSuggestions.isEmpty || initialGrouped != nil
    }

    // MARK: - Loads

    func loadSuggestions(residenceId: Int32) async {
        if isLoadingSuggestions { return }
        isLoadingSuggestions = true
        suggestionsError = nil

        do {
            let result = try await APILayer.shared.getTaskSuggestions(residenceId: residenceId)
            if let success = result as? ApiResultSuccess<TaskSuggestionsResponse>,
               let data = success.data {
                suggestions = data.suggestions
                profileCompleteness = data.profileCompleteness
                AnalyticsManager.shared.track(.onboardingSuggestionsLoaded(
                    count: data.suggestions.count,
                    profileCompleteness: data.profileCompleteness
                ))
            } else if let error = ApiResultBridge.error(from: result) {
                suggestionsError = ErrorMessageParser.parse(error.message)
            } else {
                suggestionsError = "Could not load suggestions."
            }
        } catch {
            suggestionsError = ErrorMessageParser.parse(error.localizedDescription)
        }

        isLoadingSuggestions = false
        suggestionsAttempted = true
    }

    func loadGrouped(forceRefresh: Bool = false) async {
        if isLoadingGrouped { return }
        isLoadingGrouped = true
        groupedError = nil

        do {
            let result = try await APILayer.shared.getTaskTemplatesGrouped(forceRefresh: forceRefresh)
            if let success = result as? ApiResultSuccess<TaskTemplatesGroupedResponse>,
               let data = success.data {
                grouped = data
            } else if let error = ApiResultBridge.error(from: result) {
                groupedError = ErrorMessageParser.parse(error.message)
            } else {
                groupedError = "Could not load templates."
            }
        } catch {
            groupedError = ErrorMessageParser.parse(error.localizedDescription)
        }

        isLoadingGrouped = false
    }

    // MARK: - Submit

    /// Posts the picked tasks in a single transaction via the bulk endpoint.
    /// Returns true on any successful server response (including empty
    /// selections, which short-circuit without a network call). False is
    /// terminal — the caller should show the stored `submitError`.
    func submit(residenceId: Int32, requests: [TaskCreateRequest]) async -> Bool {
        if requests.isEmpty {
            AnalyticsManager.shared.track(.onboardingTaskStepSkipped(reason: "user_skip"))
            return true
        }

        isSubmitting = true
        submitError = nil

        let request = BulkCreateTasksRequest(residenceId: residenceId, tasks: requests)
        defer { isSubmitting = false }

        do {
            let result = try await APILayer.shared.bulkCreateTasks(request: request)
            if result is ApiResultSuccess<BulkCreateTasksResponse> {
                AnalyticsManager.shared.track(.onboardingTasksCreated(count: requests.count))
                return true
            } else if let error = ApiResultBridge.error(from: result) {
                submitError = ErrorMessageParser.parse(error.message)
                return false
            } else {
                submitError = "Could not create tasks."
                return false
            }
        } catch {
            submitError = ErrorMessageParser.parse(error.localizedDescription)
            return false
        }
    }
}
