//
//  LoginViewModel.swift
//  VolnahubApp
//
//  Created by cheykrym on 09/06/2025.
//

import Foundation
import Combine

class LoginViewModel: ObservableObject {
    @Published var username: String = ""
    @Published var userId: String = ""
    @Published var password: String = ""
    @Published var isLoading: Bool = false
    @Published var isInitialLoading: Bool = true    // отдельный флаг для сплэша до завершения автологина
    @Published var showError: Bool = false
    @Published var errorMessage: String = ""
    @Published var isLoggedIn: Bool = false
    @Published var socketState: SocketService.ConnectionState
    @Published var chatLoadingState: ChatLoadingState = .idle
    @Published var hasAcceptedTerms: Bool = false
    @Published var isLoadingTerms: Bool = false
    @Published var termsContent: String = ""
    @Published var termsErrorMessage: String?
    @Published var onboardingDestination: OnboardingDestination?
    @Published var loginFlowStep: LoginFlowStep = .passwordlessRequest
    @Published var passwordlessLogin: String = "" {
        didSet {
            if passwordlessLogin.count > 32 {
                passwordlessLogin = String(passwordlessLogin.prefix(32))
            }
        }
    }
    @Published var verificationCode: String = "" {
        didSet {
            let filtered = verificationCode
                .filter { $0.isNumber }
                .prefix(Constants.verificationCodeLength)
            if filtered != verificationCode {
                verificationCode = String(filtered)
            }
        }
    }
    @Published var isSendingCode: Bool = false
    @Published var isVerifyingCode: Bool = false
    @Published var resendSecondsRemaining: Int = 0

    private let authService = AuthService()
    private let socketService = SocketService.shared
    private var cancellables = Set<AnyCancellable>()
    private var resendTimer: Timer?

    enum LoginFlowStep: Equatable {
        case passwordlessRequest
        case passwordlessVerify
        case password
        case registration
    }

    enum ChatLoadingState: Equatable {
        case idle
        case loading
    }

    enum OnboardingDestination: Equatable {
        case afterRegister
    }

    private enum DefaultsKeys {
        static let currentUser = "currentUser"
        static let userId = "userId"
    }

    init() {
        socketState = socketService.currentConnectionState
        observeSocketState()
        observeChatsReload()
//        loadStoredUser()

        // Запускаем автологин
        autoLogin()
    }

    deinit {
        resendTimer?.invalidate()
    }

    private func observeSocketState() {
        socketService.connectionStatePublisher
            .receive(on: DispatchQueue.main)
            .sink { [weak self] state in
                self?.handleSocketStateChange(state)
            }
            .store(in: &cancellables)
    }

    private func observeChatsReload() {
        NotificationCenter.default.publisher(for: .chatsReloadCompleted)
            .receive(on: DispatchQueue.main)
            .sink { [weak self] _ in
                self?.chatLoadingState = .idle
            }
            .store(in: &cancellables)
    }

    private func handleSocketStateChange(_ state: SocketService.ConnectionState) {
        socketState = state
        if state == .connected {
            triggerChatsReloadIfNeeded()
        } else {
            chatLoadingState = .idle
        }
    }

    private func triggerChatsReloadIfNeeded() {
        guard chatLoadingState != .loading else { return }
        chatLoadingState = .loading
        NotificationCenter.default.post(name: .chatsShouldRefresh, object: nil)
    }

    func autoLogin() {
        authService.autoLogin { [weak self] success, error in
            DispatchQueue.main.async {
//                self?.isLoading = false
                if success {
                    self?.loadStoredUser()
                    self?.isLoggedIn = true
                    self?.socketService.connectForCurrentUser()
                } else {
                    self?.isLoggedIn = false
                    self?.errorMessage = error ?? NSLocalizedString("Произошла ошибка.", comment: "")
                    self?.showError = false
                    self?.socketService.disconnect()
                }
                self?.isLoading = false
                self?.isInitialLoading = false
            }
        }
    }


    func login() {
        isLoading = true
        showError = false
        let trimmedLogin = passwordlessLogin.trimmingCharacters(in: .whitespacesAndNewlines)
        if trimmedLogin != passwordlessLogin {
            passwordlessLogin = trimmedLogin
        }
        username = trimmedLogin

        authService.login(username: trimmedLogin, password: password) { [weak self] success, error in
            DispatchQueue.main.async {
                self?.isLoading = false
                if success {
                    self?.loadStoredUser()
                    self?.isLoggedIn = true
                    self?.socketService.connectForCurrentUser()
                } else {
                    self?.errorMessage = error ?? NSLocalizedString("Неизвестная ошибка", comment: "")
                    self?.showError = true
                    self?.socketService.disconnect()
                }
            }
        }
    }

    func requestPasswordlessCode() {
        guard LoginViewModel.isLoginValid(passwordlessLogin) else {
            errorMessage = NSLocalizedString("Неверный логин", comment: "")
            showError = true
            return
        }

        let trimmedLogin = passwordlessLogin.trimmingCharacters(in: .whitespacesAndNewlines)

        isSendingCode = true
        showError = false

        authService.requestLoginCode(identifier: trimmedLogin) { [weak self] success, message in
            DispatchQueue.main.async {
                guard let self else { return }

                self.isSendingCode = false

                if success {
                    self.passwordlessLogin = trimmedLogin
                    self.verificationCode = ""
                    self.loginFlowStep = .passwordlessVerify
                    self.startResendTimer()
                } else {
                    if self.handlePasswordlessRedirect(message: message, login: trimmedLogin) {
                        return
                    }
                    self.errorMessage = message ?? NSLocalizedString("Не удалось отправить код.", comment: "")
                    self.showError = true
                }
            }
        }
    }

    func verifyPasswordlessCode() {
        guard verificationCode.count == Constants.verificationCodeLength,
              !passwordlessLogin.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
            return
        }

        isVerifyingCode = true
        showError = false

        authService.loginWithCode(identifier: passwordlessLogin, code: verificationCode) { [weak self] success, message in
            DispatchQueue.main.async {
                guard let self else { return }

                self.isVerifyingCode = false

                if success {
                    self.resendTimer?.invalidate()
                    self.loadStoredUser()
                    self.isLoggedIn = true
                    self.socketService.connectForCurrentUser()
                    self.verificationCode = ""
                } else {
                    self.errorMessage = message ?? NSLocalizedString("Проверьте введённый код и попробуйте снова.", comment: "")
                    self.showError = true
//                    self.verificationCode = ""
                }
            }
        }
    }

    func resendPasswordlessCode() {
        guard resendSecondsRemaining == 0 else { return }
        requestPasswordlessCode()
    }

    func showPasswordLogin() {
        resendTimer?.invalidate()
        loginFlowStep = .password
    }

    func showPasswordlessRequest() {
        loginFlowStep = .passwordlessRequest
    }

    func backToPasswordlessRequest() {
        verificationCode = ""
        loginFlowStep = .passwordlessRequest
    }

    func showRegistration() {
        loginFlowStep = .registration
    }

    
    func registerUser(username: String, password: String, invite: String?, completion: @escaping (Bool, String?) -> Void) {
        authService.register(username: username, password: password, invite: invite) { [weak self] success, message in
            DispatchQueue.main.async {
                if success {
                    self?.isLoggedIn = true // 👈 переключаем на главный экран после автологина
                    self?.loadStoredUser()
                    self?.socketService.connectForCurrentUser()
                    self?.onboardingDestination = .afterRegister
                } else {
                    self?.socketService.disconnect()
                }
                completion(success, message)
            }
        }
    }

    func logoutCurrentUser() {
        authService.logoutCurrentUser { [weak self] success, error in
            DispatchQueue.main.async {
                if success {
                    self?.loadStoredUser()
                    self?.password = ""
                    self?.isLoggedIn = true
                    self?.showError = false
                    self?.socketService.connectForCurrentUser()
                } else {
                    self?.username = ""
                    self?.userId = ""
                    self?.password = ""
                    self?.isLoggedIn = false
                    self?.errorMessage = error ?? NSLocalizedString("Ошибка при деавторизации.", comment: "")
                    self?.showError = false
                    self?.socketService.disconnect()
                }
            }
        }
    }

    
//    func logout() {
//        username = ""
//        password = ""
//        isLoggedIn = false
//        showError = false
//        errorMessage = ""
//    }

    private func loadStoredUser() {
        let defaults = UserDefaults.standard
        username = defaults.string(forKey: DefaultsKeys.currentUser) ?? ""
        userId = KeychainService.shared.get(forKey: DefaultsKeys.userId, service: username) ?? ""
        
        if AppConfig.DEBUG{ print("username: \(username) | userId: \(userId)")}
    }

    func loadTermsIfNeeded() {
        guard !isLoadingTerms else { return }

        if !termsContent.isEmpty {
            termsErrorMessage = nil
            return
        }

        isLoadingTerms = true
        termsErrorMessage = nil

        NetworkClient.shared.request(
            path: "/legal/terms",
            headers: ["Accept": "text/plain"],
            requiresAuth: false,
            callbackQueue: .main
        ) { [weak self] result in
            guard let self else { return }

            self.isLoadingTerms = false

            switch result {
            case .success(let response):
                if let content = String(data: response.data, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines),
                   !content.isEmpty {
                    self.termsContent = content
                    return
                }

                if let jsonObject = try? JSONSerialization.jsonObject(with: response.data, options: []),
                   let json = jsonObject as? [String: Any],
                   let content = (json["content"] as? String) ?? (json["text"] as? String),
                   !content.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
                    self.termsContent = content
                } else {
                    self.termsErrorMessage = NSLocalizedString("Не удалось загрузить текст правил.", comment: "")
                }
            case .failure:
                self.termsErrorMessage = NSLocalizedString("Не удалось загрузить текст правил.", comment: "")
            }
        }
    }

    func reloadTerms() {
        termsContent = ""
        termsErrorMessage = nil
        loadTermsIfNeeded()
    }

    private func startResendTimer(duration: Int = Constants.defaultResendDelay) {
        resendTimer?.invalidate()
        resendSecondsRemaining = duration

        guard duration > 0 else { return }

        resendTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] timer in
            guard let self else {
                timer.invalidate()
                return
            }

            if self.resendSecondsRemaining > 0 {
                self.resendSecondsRemaining -= 1
            } else {
                timer.invalidate()
            }
        }
    }
}

extension LoginViewModel {
    var isVerificationCodeComplete: Bool {
        verificationCode.count == Constants.verificationCodeLength
    }

    var canRequestPasswordlessCode: Bool {
        LoginViewModel.isLoginValid(passwordlessLogin) && !isSendingCode
    }

    var canVerifyPasswordlessCode: Bool {
        isVerificationCodeComplete && !isVerifyingCode
    }

    static func isLoginValid(_ login: String) -> Bool {
        let trimmed = login.trimmingCharacters(in: .whitespacesAndNewlines)
        guard trimmed == login else { return false }
        let pattern = "^[A-Za-z0-9_]{3,32}$"
        return trimmed.range(of: pattern, options: .regularExpression) != nil
    }
}

private extension LoginViewModel {
    func handlePasswordlessRedirect(message: String?, login: String) -> Bool {
        guard let message else { return false }

        switch message {
        case "otp_not_found":
            username = login
            passwordlessLogin = login
            loginFlowStep = .password
            return true
        case "account_not_found":
            username = login
            passwordlessLogin = login
            hasAcceptedTerms = false
            loginFlowStep = .registration
            return true
        default:
            return false
        }
    }

    enum Constants {
        static let verificationCodeLength = 6
        static let defaultResendDelay = 60
    }
}
