import Foundation
import SwiftUI
import Observation

@Observable
final class OnboardingViewModel {

    enum Step: Int, CaseIterable, Hashable {
        case language = 0
        case welcome = 1
        case connect = 2
        case ready = 3
    }

    // Navigation — NavigationStack path (language is the root, not in the path)
    var navPath: NavigationPath = NavigationPath()

    // Input
    var serverNameInput: String = ""
    var serverURLInput: String = ""
    var tokenIdInput: String = ""
    var tokenSecretInput: String = ""

    // URL validation
    var serverURLError: String? = nil

    // Verification phases
    enum VerifyPhase {
        case idle
        case checkingServer
        case serverOK(appName: String)
        case checkingToken
        case done(appName: String, userName: String?)
        case failed(phase: String, error: BookStackError)
    }
    var verifyPhase: VerifyPhase = .idle

    // Completion
    var isComplete: Bool = false
    /// Set to true after successfully adding a server in the Settings "Add Server" flow.
    var isAddComplete: Bool = false
    /// When true, skips the ready step navigation (used in Add Server sheet).
    var isAddServerMode: Bool = false

    // MARK: - Navigation

    func push(_ step: Step) {
        navPath.append(step)
    }

    func resetVerification() {
        verifyPhase = .idle
    }

    // MARK: - URL Validation

    func validateServerURL() -> Bool {
        var url = serverURLInput.trimmingCharacters(in: .whitespacesAndNewlines)
        guard !url.isEmpty else {
            serverURLError = L("onboarding.server.error.empty")
            return false
        }
        // Auto-prefix https:// if missing
        if !url.hasPrefix("http://") && !url.hasPrefix("https://") {
            url = "https://" + url
            serverURLInput = url
        }
        // Strip trailing slash
        if url.hasSuffix("/") {
            url = String(url.dropLast())
            serverURLInput = url
        }
        guard URL(string: url) != nil else {
            serverURLError = L("onboarding.server.error.invalid")
            return false
        }
        serverURLError = nil
        return true
    }

    var isHTTP: Bool {
        serverURLInput.hasPrefix("http://") && !serverURLInput.hasPrefix("https://")
    }

    // MARK: - Verification

    func verifyAndSave() async {
        let url = serverURLInput
        let tokenId = tokenIdInput
        let tokenSecret = tokenSecretInput

        AppLog(.info, "Starting onboarding verification for \(url)", category: "Onboarding")

        // Phase 1: show "reaching server" while we attempt the connection
        verifyPhase = .checkingServer

        let info: APIInfo
        do {
            // Single request to /api/system covers both server reachability and token validity
            info = try await BookStackAPI.shared.verifyConnection(url: url, tokenId: tokenId, tokenSecret: tokenSecret)
        } catch let error as BookStackError {
            // Distinguish server-unreachable errors from auth errors for the UI
            let phase: String
            switch error {
            case .unauthorized, .forbidden:
                phase = "token"
            case .httpError(let code, _) where code == 403:
                phase = "token"
            default:
                phase = "server"
            }
            AppLog(.error, "Verification failed (\(phase)): \(error.localizedDescription)", category: "Onboarding")
            verifyPhase = .failed(phase: phase, error: error)
            return
        } catch {
            AppLog(.error, "Verification failed: \(error.localizedDescription)", category: "Onboarding")
            verifyPhase = .failed(phase: "server", error: .unknown(error.localizedDescription))
            return
        }

        // Both server and token confirmed — show intermediate state briefly
        let appName = info.appName ?? "BookStack"
        verifyPhase = .serverOK(appName: appName)

        // Auto-populate server name from API if the user left it blank
        if serverNameInput.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
            serverNameInput = appName
        }

        // Configure the shared API client with validated credentials
        await BookStackAPI.shared.configure(serverURL: url, tokenId: tokenId, tokenSecret: tokenSecret)
        verifyPhase = .checkingToken

        // Attempt to fetch user info (non-fatal — some installs restrict /api/users)
        let userName = try? await BookStackAPI.shared.fetchCurrentUser().name

        // Create and persist a ServerProfile via the shared store
        let profile = ServerProfile(
            id: UUID(),
            name: serverNameInput.trimmingCharacters(in: .whitespacesAndNewlines),
            serverURL: url
        )
        ServerProfileStore.shared.addProfile(profile, tokenId: tokenId, tokenSecret: tokenSecret)

        AppLog(.info, "Onboarding complete — connected to \(appName)\(userName.map { " as \($0)" } ?? "")", category: "Onboarding")
        verifyPhase = .done(appName: appName, userName: userName)

        if isAddServerMode {
            // In the "Add Server" sheet: signal completion so the sheet dismisses
            isAddComplete = true
        } else {
            // Normal onboarding: navigate to the ready step
            navPath.append(Step.ready)
        }
    }

    // MARK: - Complete

    func completeOnboarding() {
        UserDefaults.standard.set(true, forKey: "onboardingComplete")
        AppLog(.info, "Onboarding marked complete", category: "Onboarding")
        isComplete = true
    }
}
