import Foundation
import ComposeApp
import Combine

/// ViewModel for user login.
/// Observes DataManagerObservable for authentication state.
/// Kicks off API calls that update DataManager, letting views react to cache updates.
@MainActor
class LoginViewModel: ObservableObject {
    // MARK: - Published Properties (from DataManager observation)
    @Published var currentUser: User?
    @Published var isAuthenticated: Bool = false

    // MARK: - Local State
    @Published var username: String = ""
    @Published var password: String = ""
    @Published var isLoading: Bool = false
    @Published var errorMessage: String?
    @Published var isVerified: Bool = false

    // Callback for successful login
    var onLoginSuccess: ((Bool) -> Void)?

    // MARK: - Private Properties
    private var cancellables = Set<AnyCancellable>()
    private let dataManager: DataManagerObservable

    // MARK: - Initialization
    /// - Parameter dataManager: Observable cache the VM subscribes to.
    ///   Defaults to the shared singleton.
    init(dataManager: DataManagerObservable = .shared) {
        self.dataManager = dataManager

        // Seed from current cache so snapshot tests/previews render
        // populated state without waiting for Combine's async dispatch.
        self.currentUser = dataManager.currentUser
        self.isAuthenticated = dataManager.isAuthenticated

        // Observe injected DataManagerObservable for authentication state
        dataManager.$currentUser
            .receive(on: DispatchQueue.main)
            .sink { [weak self] user in
                self?.currentUser = user
            }
            .store(in: &cancellables)

        dataManager.$isAuthenticated
            .receive(on: DispatchQueue.main)
            .sink { [weak self] isAuth in
                self?.isAuthenticated = isAuth
            }
            .store(in: &cancellables)
    }

    // MARK: - Public Methods
    func login() {
        guard !username.isEmpty else {
            errorMessage = "Username is required"
            return
        }

        guard !password.isEmpty else {
            errorMessage = "Password is required"
            return
        }

        isLoading = true
        errorMessage = nil

        if UITestRuntime.shouldMockAuth {
            // Deterministic UI-test auth path scoped behind launch args.
            if username == "testuser" && password == "TestPass123!" {
                isVerified = true
                isLoading = false
                onLoginSuccess?(true)
            } else {
                isLoading = false
                errorMessage = "Invalid username or password"
            }
            return
        }

        Task {
            do {
                let result = try await APILayer.shared.login(
                    request: LoginRequest(username: username, password: password)
                )

                if let success = result as? ApiResultSuccess<AuthResponse>,
                   let response = success.data {
                    // APILayer.login already stores token in DataManager
                    // currentUser will be updated via DataManagerObservable observation
                    self.isVerified = response.user.verified
                    self.isLoading = false

                    #if DEBUG
                    print("Login successful!")
                    print("User: \(response.user.username ?? "unknown"), Verified: \(self.isVerified)")
                    #endif

                    // Share token and API URL with widget extension
                    WidgetDataManager.shared.saveAuthToken(response.token)
                    WidgetDataManager.shared.saveAPIBaseURL(ApiClient.shared.getBaseUrl())

                    // Track successful login
                    AnalyticsManager.shared.track(.userSignedIn(method: "email"))

                    // Lookups are already initialized by APILayer.login() internally
                    // (see APILayer.kt line 1205) — no need to call again here

                    // Call login success callback
                    self.onLoginSuccess?(self.isVerified)
                } else if let error = ApiResultBridge.error(from: result) {
                    self.isLoading = false
                    self.handleLoginError(error)
                } else {
                    self.isLoading = false
                    self.errorMessage = "Failed to sign in"
                }
            } catch {
                self.isLoading = false
                self.errorMessage = ErrorMessageParser.parse(error.localizedDescription)
            }
        }
    }

    private func handleLoginError(_ error: ApiResultError) {
        // Check for specific error codes and provide user-friendly messages
        if let code = error.code?.intValue {
            switch code {
            case 401:
                self.errorMessage = "Invalid username or password"
            case 403:
                self.errorMessage = "Access denied. Please check your credentials."
            case 404:
                self.errorMessage = "Service not found. Please try again later."
            case 409:
                // Conflict - let backend message explain the issue
                self.errorMessage = ErrorMessageParser.parse(error.message)
            case 400:
                // Bad request - validation errors from backend
                self.errorMessage = ErrorMessageParser.parse(error.message)
            case 500...599:
                self.errorMessage = "Server error. Please try again later."
            default:
                self.errorMessage = ErrorMessageParser.parse(error.message)
            }
        } else {
            self.errorMessage = ErrorMessageParser.parse(error.message)
        }
        #if DEBUG
        print("API Error: \(error.message)")
        #endif
    }

    func logout() {
        Task {
            // APILayer.logout clears DataManager
            do {
                _ = try await APILayer.shared.logout()
            } catch {
                #if DEBUG
                print("Logout error: \(error)")
                #endif
            }

            SubscriptionCacheWrapper.shared.clear()
            PushNotificationManager.shared.clearRegistrationCache()

            // Clear widget task data
            WidgetDataManager.shared.clearCache()
            WidgetDataManager.shared.clearAuthToken()

            // Clear authenticated image cache
            AuthenticatedImage.clearCache()

            // Reset local state
            self.isVerified = false
            self.currentUser = nil
            self.username = ""
            self.password = ""
            self.errorMessage = nil

            #if DEBUG
            print("Logged out - all state reset")
            #endif
        }
    }

    func clearError() {
        errorMessage = nil
    }
}
