//
//  AuthManager.swift
//  AppClientBaseSwift
//
//  Authentication state management
//  Quản lý trạng thái xác thực
//

import Foundation
import Security
import Combine

// MARK: - Auth State
// Trạng thái xác thực

/// Authentication state enumeration
/// Enum trạng thái xác thực
enum AuthState: Equatable {
    case unknown
    case unauthenticated
    case authenticated(User)

    var isAuthenticated: Bool {
        if case .authenticated = self {
            return true
        }
        return false
    }

    var user: User? {
        if case .authenticated(let user) = self {
            return user
        }
        return nil
    }
}

// MARK: - Auth Manager
// Quản lý xác thực

/// Main authentication manager
/// Quản lý xác thực chính
final class AuthManager: ObservableObject {

    // MARK: - Properties

    /// Shared singleton instance
    /// Instance singleton dùng chung
    @MainActor static let shared = AuthManager()

    /// Current authentication state
    /// Trạng thái xác thực hiện tại
    @MainActor @Published private(set) var authState: AuthState = .unknown

    /// Access token from Keychain
    /// Access token từ Keychain
    @MainActor var accessToken: String? {
        KeychainHelper.read(key: StorageKeys.accessToken)
    }

    /// Refresh token from Keychain
    /// Refresh token từ Keychain
    @MainActor var refreshToken: String? {
        KeychainHelper.read(key: StorageKeys.refreshToken)
    }

    /// Whether user is currently authenticated
    /// Người dùng có đang xác thực không
    @MainActor var isAuthenticated: Bool {
        authState.isAuthenticated
    }

    /// Current authenticated user
    /// Người dùng đã xác thực hiện tại
    @MainActor var currentUser: User? {
        authState.user
    }

    // MARK: - Init

    private init() {}

    // MARK: - Public Methods

    /// Set authenticated state with user (for mock login)
    /// Đặt trạng thái authenticated với user (cho mock login)
    @MainActor func setAuthenticated(user: User) {
        authState = .authenticated(user)
    }

    // MARK: - Public Methods

    /// Initialize auth state on app launch
    /// Khởi tạo trạng thái xác thực khi app khởi động
    @MainActor func initialize() async {
        guard accessToken != nil else {
            authState = .unauthenticated
            return
        }

        // Try to load cached user
        // Thử tải user đã cache
        if let userData = UserDefaults.standard.data(forKey: StorageKeys.userData),
            let user = try? JSONDecoder().decode(User.self, from: userData)
        {
            authState = .authenticated(user)
        } else {
            // Fetch user from API
            // Lấy user từ API
            await refreshCurrentUser()
        }
    }

    /// Login with email and password using OAuth2 Password Grant
    /// Đăng nhập với email và mật khẩu sử dụng OAuth2 Password Grant
    /// - Parameters:
    ///   - email: User email / Email người dùng
    ///   - password: User password / Mật khẩu người dùng
    @MainActor func login(email: String, password: String) async throws {
        // OAuth2 Password Grant
        // OAuth2 Password Grant
        let formData: [String: String] = [
            "grant_type": "password",
            "client_id": APIConfig.oauthClientId,
            "client_secret": APIConfig.oauthClientSecret,
            "username": email,
            "password": password,
            "scope": APIConfig.oauthScope
        ]

        let tokenResponse: OAuthTokenResponse = try await APIService.shared.postForm(
            endpoint: APIConfig.tokenEndpoint,
            formData: formData
        )

        // Save tokens to Keychain
        // Lưu tokens vào Keychain
        KeychainHelper.save(key: StorageKeys.accessToken, value: tokenResponse.accessToken)
        if let refreshToken = tokenResponse.refreshToken {
            KeychainHelper.save(key: StorageKeys.refreshToken, value: refreshToken)
        }

        // Fetch user info from API
        // Lấy thông tin user từ API
        await fetchCurrentUser()
    }

    /// Register new user
    /// Đăng ký người dùng mới
    /// - Parameters:
    ///   - firstName: User first name / Tên người dùng
    ///   - lastName: User last name / Họ người dùng
    ///   - email: User email / Email người dùng
    ///   - password: User password / Mật khẩu người dùng
    @MainActor func register(firstName: String, lastName: String, email: String, password: String) async throws {
        struct RegisterRequest: Encodable {
            let firstName: String
            let lastName: String
            let email: String
            let password: String
        }

        struct RegisterData: Decodable {
            let userId: String
            let email: String
        }

        let request = RegisterRequest(
            firstName: firstName,
            lastName: lastName,
            email: email,
            password: password
        )
        
        // Use APIResponse wrapper for register
        // Dùng APIResponse wrapper cho đăng ký
        let response: APIResponse<RegisterData> = try await APIService.shared.post(
            endpoint: "/auth/register",
            body: request
        )
        
        // Unwrap response or throw error
        // Unwrap response hoặc throw error
        _ = try response.unwrap()

        // Auto login after successful registration
        // Tự động đăng nhập sau khi đăng ký thành công
        try await login(email: email, password: password)
    }

    /// Logout current user
    /// Đăng xuất người dùng hiện tại
    @MainActor func logout() {
        // Clear tokens from Keychain
        // Xóa tokens khỏi Keychain
        KeychainHelper.delete(key: StorageKeys.accessToken)
        KeychainHelper.delete(key: StorageKeys.refreshToken)

        // Clear cached user data
        // Xóa dữ liệu user đã cache
        UserDefaults.standard.removeObject(forKey: StorageKeys.userData)

        authState = .unauthenticated
    }

    /// Handle unauthorized response (401)
    /// Xử lý response unauthorized (401)
    @MainActor func handleUnauthorized() {
        // Try refresh token first, then logout
        // Thử refresh token trước, sau đó logout
        Task {
            let success = await refreshTokens()
            if !success {
                logout()
            }
        }
    }

    /// Fetch current user from API
    /// Lấy thông tin user hiện tại từ API
    @MainActor func fetchCurrentUser() async {
        do {
            // Fetch user with wrapper response
            // Lấy user với wrapper response
            let response: APIResponse<User> = try await APIService.shared.get(endpoint: "/users/me")
            
            // Unwrap response data
            // Unwrap dữ liệu response
            let user = try response.unwrap()

            // Cache user data
            // Cache dữ liệu user
            if let userData = try? JSONEncoder().encode(user) {
                UserDefaults.standard.set(userData, forKey: StorageKeys.userData)
            }

            authState = .authenticated(user)
            print("✅ User fetched successfully: \(user.email)")
            
        } catch let error as APIError {
            // Enhanced error logging
            // Ghi log lỗi chi tiết hơn
            print("❌ Failed to fetch user: \(error.localizedDescription)")
            
            if case .decodingError(let decodingError) = error {
                print("💡 Suggestion: Check if the API response matches the APIResponse<User> structure")
                print("   Expected wrapper: { success: Bool, data: User, error: String?, pagination: Pagination? }")
                print("   Decoding error: \(decodingError)")
            }
            
            authState = .unauthenticated
        } catch {
            print("❌ Failed to fetch user: \(error.localizedDescription)")
            authState = .unauthenticated
        }
    }

    /// Refresh current user from cache or API
    /// Làm mới thông tin user từ cache hoặc API
    @MainActor func refreshCurrentUser() async {
        await fetchCurrentUser()
    }

    // MARK: - Private Methods

    /// Refresh access token using OAuth2 refresh_token grant
    /// Làm mới access token sử dụng OAuth2 refresh_token grant
    /// - Returns: Whether refresh was successful / Refresh có thành công không
    @MainActor private func refreshTokens() async -> Bool {
        guard let refreshToken = refreshToken else {
            return false
        }

        // OAuth2 Refresh Token Grant
        // OAuth2 Refresh Token Grant
        let formData: [String: String] = [
            "grant_type": "refresh_token",
            "refresh_token": refreshToken
        ]

        do {
            let response: OAuthTokenResponse = try await APIService.shared.postForm(
                endpoint: APIConfig.tokenEndpoint,
                formData: formData
            )

            // Save new tokens
            // Lưu tokens mới
            KeychainHelper.save(key: StorageKeys.accessToken, value: response.accessToken)
            if let newRefreshToken = response.refreshToken {
                KeychainHelper.save(key: StorageKeys.refreshToken, value: newRefreshToken)
            }

            return true
        } catch {
            print("Token refresh failed: \(error)")
            return false
        }
    }
}

// MARK: - Keychain Helper
// Helper Keychain

/// Helper for Keychain operations
/// Helper cho các thao tác Keychain
enum KeychainHelper {

    /// Save value to Keychain
    /// Lưu giá trị vào Keychain
    static func save(key: String, value: String) {
        guard let data = value.data(using: .utf8) else { return }

        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: AppConstants.keychainService,
            kSecAttrAccount as String: key,
            kSecValueData as String: data,
        ]

        // Delete existing
        // Xóa existing
        SecItemDelete(query as CFDictionary)

        // Add new
        // Thêm mới
        SecItemAdd(query as CFDictionary, nil)
    }

    /// Read value from Keychain
    /// Đọc giá trị từ Keychain
    static func read(key: String) -> String? {
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: AppConstants.keychainService,
            kSecAttrAccount as String: key,
            kSecReturnData as String: true,
            kSecMatchLimit as String: kSecMatchLimitOne,
        ]

        var dataTypeRef: AnyObject?
        let status = SecItemCopyMatching(query as CFDictionary, &dataTypeRef)

        guard status == errSecSuccess,
            let data = dataTypeRef as? Data,
            let value = String(data: data, encoding: .utf8)
        else {
            return nil
        }

        return value
    }

    /// Delete value from Keychain
    /// Xóa giá trị khỏi Keychain
    static func delete(key: String) {
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: AppConstants.keychainService,
            kSecAttrAccount as String: key,
        ]

        SecItemDelete(query as CFDictionary)
    }
}
