import Foundation
import SwiftUI

@Observable
final class AuthViewModel {
    var email = ""
    var password = ""
    var confirmPassword = ""
    var username = ""
    var confirmationCode = ""

    var isLoading = false
    var errorMessage: String?
    var showConfirmation = false
    var registrationMessage: String?

    var serverHost = Constants.defaultHost
    var serverPort = String(Constants.defaultPort)

    var hasSavedCredentials = false
    var isBiometricLoading = false

    enum AuthMode {
        case login, register, pairing
    }
    var mode: AuthMode = .login

    func checkSavedCredentials() {
        hasSavedCredentials = KeychainService.hasSavedCredentials() && KeychainService.isBiometricAvailable()
    }

    func login(appState: AppState) async {
        guard !email.isEmpty, !password.isEmpty else {
            errorMessage = "Email and password are required"
            return
        }

        isLoading = true
        errorMessage = nil

        // Only connect if not already connected
        if await !appState.chatClient.isConnected {
            do {
                let port = UInt16(serverPort) ?? Constants.defaultPort
                try await appState.chatClient.connect(host: serverHost, port: port)
            } catch {
                isLoading = false
                errorMessage = "Connection failed: \(error.localizedDescription)"
                return
            }
        }

        let (success, message) = await appState.chatClient.login(email: email, password: password)
        isLoading = false

        if success {
            appState.email = email
            appState.isLoggedIn = true
            appState.connectionStatus = .connected
            appState.startConnectionMonitor()
            if let userId = await appState.chatClient.userId {
                appState.currentUser = User(id: userId, username: await appState.chatClient.username, email: email)
            }

            // Save credentials for biometric login next time
            if KeychainService.isBiometricAvailable() {
                let port = UInt16(serverPort) ?? Constants.defaultPort
                try? KeychainService.saveCredentials(
                    email: email, password: password,
                    host: serverHost, port: port
                )
            }

            // Clear password from memory after successful login
            password = ""
            confirmPassword = ""
        } else {
            errorMessage = message
        }
    }

    func biometricLogin(appState: AppState) async {
        isBiometricLoading = true
        errorMessage = nil

        do {
            let creds = try KeychainService.loadCredentials()
            email = creds.email
            password = creds.password
            serverHost = creds.host
            serverPort = String(creds.port)
            isBiometricLoading = false

            await login(appState: appState)

            // If login failed, reset to defaults so the form isn't stuck on stale values
            if !appState.isLoggedIn {
                serverHost = Constants.defaultHost
                serverPort = String(Constants.defaultPort)
                password = ""
                KeychainService.deleteCredentials()
                hasSavedCredentials = false
            }
        } catch KeychainService.KeychainError.biometricFailed {
            isBiometricLoading = false
            // User cancelled — just let them type manually
        } catch {
            isBiometricLoading = false
            errorMessage = error.localizedDescription
        }
    }

    func register(appState: AppState) async {
        guard !email.isEmpty, !password.isEmpty, !username.isEmpty else {
            errorMessage = "All fields are required"
            return
        }
        guard password == confirmPassword else {
            errorMessage = "Passwords don't match"
            return
        }

        isLoading = true
        errorMessage = nil

        #if DEBUG
        print("DEBUG register: connecting to \(serverHost):\(serverPort)")
        #endif
        if await !appState.chatClient.isConnected {
            do {
                let port = UInt16(serverPort) ?? Constants.defaultPort
                try await appState.chatClient.connect(host: serverHost, port: port)
                #if DEBUG
                print("DEBUG register: connected successfully")
                #endif
            } catch {
                isLoading = false
                #if DEBUG
                print("DEBUG register: connection failed - \(error)")
                #endif
                errorMessage = "Connection failed: \(error.localizedDescription)"
                return
            }
        }

        #if DEBUG
        print("DEBUG register: calling chatClient.register")
        #endif
        let (success, message) = await appState.chatClient.register(username: username, password: password, email: email)
        isLoading = false

        #if DEBUG
        print("DEBUG AuthViewModel: register returned success=\(success), message=\(message)")
        #endif

        if success {
            registrationMessage = message
            showConfirmation = true
            #if DEBUG
            print("DEBUG AuthViewModel: showConfirmation set to true")
            #endif
        } else {
            errorMessage = message
            #if DEBUG
            print("DEBUG AuthViewModel: errorMessage set to \(message)")
            #endif
        }
    }

    func confirmRegistration(appState: AppState) async {
        guard !confirmationCode.isEmpty else {
            errorMessage = "Enter the confirmation code"
            return
        }

        isLoading = true
        errorMessage = nil

        let (success, message) = await appState.chatClient.confirmRegistration(
            email: email, username: username, code: confirmationCode
        )
        isLoading = false

        if success {
            registrationMessage = message
            // Auto-login after registration
            await login(appState: appState)
        } else {
            errorMessage = message
        }
    }
}
