/// User Info Remote Data Source
///
/// Handles API calls for fetching user information.
library;

import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:worker/core/errors/exceptions.dart';
import 'package:worker/core/network/dio_client.dart';
import 'package:worker/features/account/data/models/user_info_model.dart';

/// User Info Remote Data Source
///
/// Provides methods for:
/// - Fetching current user information from API
/// - Uses existing Frappe authentication (cookies/tokens)
class UserInfoRemoteDataSource {
  UserInfoRemoteDataSource(this._dioClient);

  final DioClient _dioClient;

  /// Get User Info
  ///
  /// Fetches the current authenticated user's information.
  /// Uses existing Frappe session cookies/tokens for authentication.
  ///
  /// API: POST https://land.dbiz.com/api/method/building_material.building_material.api.user.get_user_info
  /// Request: Empty POST (no body required)
  ///
  /// Response structure:
  /// ```json
  /// {
  ///   "message": {
  ///     "user_id": "...",
  ///     "full_name": "...",
  ///     "email": "...",
  ///     "phone_number": "...",
  ///     "role": "customer",
  ///     "status": "active",
  ///     "loyalty_tier": "gold",
  ///     "total_points": 1000,
  ///     "available_points": 800,
  ///     "expiring_points": 200,
  ///     // ... other fields
  ///   }
  /// }
  /// ```
  ///
  /// Throws:
  /// - [UnauthorizedException] if user not authenticated (401)
  /// - [NotFoundException] if endpoint not found (404)
  /// - [ServerException] if server error occurs (500+)
  /// - [NetworkException] for other network errors
  Future<UserInfoModel> getUserInfo() async {
    try {
      debugPrint('🔵 [UserInfoDataSource] Fetching user info...');
      final startTime = DateTime.now();

      // Make POST request with empty body
      // Authentication is handled by auth interceptor (uses existing session)
      final response = await _dioClient.post<Map<String, dynamic>>(
        '/api/method/building_material.building_material.api.user.get_user_info',
        data: const <String, dynamic>{}, // Empty body as per API spec
      );

      final duration = DateTime.now().difference(startTime);
      debugPrint('🟢 [UserInfoDataSource] Response received in ${duration.inMilliseconds}ms');
      debugPrint('🟢 [UserInfoDataSource] Status: ${response.statusCode}');
      debugPrint('🟢 [UserInfoDataSource] Data: ${response.data}');

      // Check response status and data
      if (response.statusCode == 200 && response.data != null) {
        // Parse response to model
        final model = UserInfoModel.fromJson(response.data!);
        debugPrint('✅ [UserInfoDataSource] Successfully parsed user: ${model.fullName}');
        return model;
      } else {
        throw ServerException(
          'Failed to get user info: ${response.statusCode}',
          response.statusCode,
        );
      }
    } on DioException catch (e) {
      // Handle specific HTTP status codes
      if (e.response?.statusCode == 401) {
        throw const UnauthorizedException(
          'Session expired. Please login again.',
        );
      } else if (e.response?.statusCode == 403) {
        throw const ForbiddenException();
      } else if (e.response?.statusCode == 404) {
        throw NotFoundException('User info endpoint not found');
      } else if (e.response?.statusCode != null &&
          e.response!.statusCode! >= 500) {
        throw ServerException(
          'Server error: ${e.response?.statusMessage ?? "Unknown error"}',
          e.response?.statusCode,
        );
      } else if (e.type == DioExceptionType.connectionTimeout ||
          e.type == DioExceptionType.receiveTimeout) {
        throw const TimeoutException();
      } else if (e.type == DioExceptionType.connectionError) {
        throw const NoInternetException();
      } else {
        throw NetworkException(
          e.message ?? 'Failed to get user info',
          statusCode: e.response?.statusCode,
        );
      }
    } catch (e) {
      // Handle unexpected errors
      if (e is ServerException ||
          e is UnauthorizedException ||
          e is NetworkException ||
          e is NotFoundException) {
        rethrow;
      }
      throw ServerException('Unexpected error: $e');
    }
  }

  /// Refresh User Info
  ///
  /// Same as getUserInfo but with force refresh parameter.
  /// Useful when you want to bypass cache and get fresh data.
  Future<UserInfoModel> refreshUserInfo() async {
    // For now, same as getUserInfo
    // Could add cache-busting headers in the future if needed
    return getUserInfo();
  }

  /// Update User Info
  ///
  /// Updates the current user's profile information.
  ///
  /// API: POST https://land.dbiz.com/api/method/building_material.building_material.api.user.update_user_info
  ///
  /// Request body:
  /// ```json
  /// {
  ///   "full_name": "...",
  ///   "date_of_birth": "YYYY-MM-DD",
  ///   "gender": "Male/Female",
  ///   "company_name": "...",
  ///   "tax_code": "...",
  ///   "avatar_base64": null | base64_string,
  ///   "id_card_front_base64": null | base64_string,
  ///   "id_card_back_base64": null | base64_string,
  ///   "certificates_base64": [] | [base64_string, ...]
  /// }
  /// ```
  ///
  /// Throws:
  /// - [UnauthorizedException] if user not authenticated (401)
  /// - [ServerException] if server error occurs (500+)
  /// - [NetworkException] for other network errors
  Future<UserInfoModel> updateUserInfo(Map<String, dynamic> data) async {
    try {
      debugPrint('🔵 [UserInfoDataSource] Updating user info...');
      debugPrint('🔵 [UserInfoDataSource] Data: $data');
      final startTime = DateTime.now();

      // Make POST request with update data
      final response = await _dioClient.post<Map<String, dynamic>>(
        '/api/method/building_material.building_material.api.user.update_user_info',
        data: data,
      );

      final duration = DateTime.now().difference(startTime);
      debugPrint('🟢 [UserInfoDataSource] Update response received in ${duration.inMilliseconds}ms');
      debugPrint('🟢 [UserInfoDataSource] Status: ${response.statusCode}');

      // Check response status
      if (response.statusCode == 200) {
        // After successful update, fetch fresh user info
        debugPrint('✅ [UserInfoDataSource] Successfully updated user info');
        return await getUserInfo();
      } else {
        throw ServerException(
          'Failed to update user info: ${response.statusCode}',
          response.statusCode,
        );
      }
    } on DioException catch (e) {
      // Handle specific HTTP status codes
      if (e.response?.statusCode == 401) {
        throw const UnauthorizedException(
          'Session expired. Please login again.',
        );
      } else if (e.response?.statusCode == 403) {
        throw const ForbiddenException();
      } else if (e.response?.statusCode == 404) {
        throw NotFoundException('Update user info endpoint not found');
      } else if (e.response?.statusCode != null &&
          e.response!.statusCode! >= 500) {
        throw ServerException(
          'Server error: ${e.response?.statusMessage ?? "Unknown error"}',
          e.response?.statusCode,
        );
      } else if (e.type == DioExceptionType.connectionTimeout ||
          e.type == DioExceptionType.receiveTimeout) {
        throw const TimeoutException();
      } else if (e.type == DioExceptionType.connectionError) {
        throw const NoInternetException();
      } else {
        throw NetworkException(
          e.message ?? 'Failed to update user info',
          statusCode: e.response?.statusCode,
        );
      }
    } catch (e) {
      // Handle unexpected errors
      if (e is ServerException ||
          e is UnauthorizedException ||
          e is NetworkException ||
          e is NotFoundException) {
        rethrow;
      }
      throw ServerException('Unexpected error: $e');
    }
  }
}
