import 'dart:convert';
import 'package:get/get.dart';
import 'package:http/http.dart' as http;
import 'package:image_picker/image_picker.dart';
import 'package:intl/intl.dart';

import 'package:on_field_work/helpers/services/auth_service.dart';
import 'package:on_field_work/helpers/services/api_endpoints.dart';
import 'package:on_field_work/helpers/services/storage/local_storage.dart';
import 'package:jwt_decoder/jwt_decoder.dart';
import 'package:on_field_work/model/dashboard/project_progress_model.dart';
import 'package:on_field_work/model/dashboard/dashboard_tasks_model.dart';
import 'package:on_field_work/model/dashboard/dashboard_teams_model.dart';
import 'package:on_field_work/helpers/services/app_logger.dart';
import 'package:on_field_work/model/document/document_filter_model.dart';
import 'package:on_field_work/model/document/documents_list_model.dart';
import 'package:on_field_work/model/document/master_document_tags.dart';
import 'package:on_field_work/model/document/master_document_type_model.dart';
import 'package:on_field_work/model/document/document_details_model.dart';
import 'package:on_field_work/model/document/document_version_model.dart';
import 'package:on_field_work/model/attendance/organization_per_project_list_model.dart';
import 'package:on_field_work/model/tenant/tenant_services_model.dart';
import 'package:on_field_work/model/dailyTaskPlanning/daily_task_model.dart';
import 'package:on_field_work/model/dailyTaskPlanning/daily_progress_report_filter_response_model.dart';
import 'package:on_field_work/model/all_organization_model.dart';
import 'package:on_field_work/model/dashboard/pending_expenses_model.dart';
import 'package:on_field_work/model/dashboard/expense_type_report_model.dart';
import 'package:on_field_work/model/dashboard/monthly_expence_model.dart';
import 'package:on_field_work/model/finance/expense_category_model.dart';
import 'package:on_field_work/model/finance/currency_list_model.dart';
import 'package:on_field_work/model/finance/payment_payee_request_model.dart';
import 'package:on_field_work/model/finance/payment_request_list_model.dart';
import 'package:on_field_work/model/finance/payment_request_filter.dart';
import 'package:on_field_work/model/finance/payment_request_details_model.dart';
import 'package:on_field_work/model/finance/advance_payment_model.dart';
import 'package:on_field_work/model/service_project/service_projects_list_model.dart';
import 'package:on_field_work/model/service_project/service_projects_details_model.dart';
import 'package:on_field_work/model/service_project/job_list_model.dart';
import 'package:on_field_work/model/service_project/service_project_job_detail_model.dart';
import 'package:on_field_work/model/service_project/job_attendance_logs_model.dart';
import 'package:on_field_work/model/service_project/job_allocation_model.dart';
import 'package:on_field_work/model/service_project/service_project_branches_model.dart';
import 'package:on_field_work/model/service_project/job_status_response.dart';
import 'package:on_field_work/model/service_project/job_comments.dart';
import 'package:on_field_work/model/employees/employee_model.dart';
import 'package:on_field_work/model/infra_project/infra_project_list.dart';
import 'package:on_field_work/model/infra_project/infra_project_details.dart';
import 'package:on_field_work/model/dashboard/collection_overview_model.dart';
import 'package:on_field_work/model/dashboard/purchase_invoice_model.dart';


class ApiService {
  static const bool enableLogs = true;
  static const Duration extendedTimeout = Duration(seconds: 60);

  static Future<String?> _getToken() async {
    final token = LocalStorage.getJwtToken();

    if (token == null) {
      logSafe("No JWT token found. Logging out...");
      await LocalStorage.logout();
      return null;
    }

    try {
      if (JwtDecoder.isExpired(token)) {
        logSafe("Access token is expired. Attempting refresh...");
        final refreshed = await AuthService.refreshToken();
        if (refreshed) {
          return LocalStorage.getJwtToken();
        } else {
          logSafe("Token refresh failed. Logging out immediately...");
          await LocalStorage.logout();
          return null;
        }
      }

      final expirationDate = JwtDecoder.getExpirationDate(token);
      final now = DateTime.now();
      final difference = expirationDate.difference(now);

      if (difference.inMinutes < 2) {
        logSafe(
            "Access token is about to expire in ${difference.inSeconds}s. Refreshing...");
        final refreshed = await AuthService.refreshToken();
        if (refreshed) {
          return LocalStorage.getJwtToken();
        } else {
          logSafe("Token refresh failed (near expiry). Logging out...");
          await LocalStorage.logout();
          return null;
        }
      }
    } catch (e) {
      logSafe("Token decoding error: $e", level: LogLevel.error);
      await LocalStorage.logout();
      return null;
    }

    return token;
  }

  static Map<String, String> _headers(String token) => {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer $token',
      };

  static void _log(String message, {LogLevel level = LogLevel.info}) {
    if (enableLogs) {
      logSafe(message, level: level);
    }
  }

  static dynamic _parseResponse(http.Response response, {String label = ''}) {
    _log("$label Response: ${response.body}");
    try {
      final json = jsonDecode(response.body);
      if (response.statusCode == 200 && json['success'] == true) {
        return json['data'];
      }
      _log("API Error [$label]: ${json['message'] ?? 'Unknown error'}");
    } catch (e) {
      _log("Response parsing error [$label]: $e");
    }
    return null;
  }

  static dynamic _parseResponseForAllData(http.Response response,
      {String label = ''}) {
    _log("$label Response: ${response.body}");

    try {
      final body = response.body.trim();
      if (body.isEmpty) throw FormatException("Empty response body");

      final json = jsonDecode(body);
      if (response.statusCode == 200 && json['success'] == true) {
        return json;
      }

      _log("API Error [$label]: ${json['message'] ?? 'Unknown error'}");
    } catch (e) {
      _log("Response parsing error [$label]: $e");
    }

    return null;
  }

  static Future<http.Response?> _getRequest(
    String endpoint, {
    Map<String, String>? queryParams,
    bool hasRetried = false,
  }) async {
    String? token = await _getToken();
    if (token == null) {
      logSafe("Token is null. Forcing logout from GET request.",
          level: LogLevel.error);
      await LocalStorage.logout();
      return null;
    }

    final uri = Uri.parse("${ApiEndpoints.baseUrl}$endpoint")
        .replace(queryParameters: queryParams);

    logSafe("Initiating GET request", level: LogLevel.debug);
    logSafe("URL: $uri", level: LogLevel.debug);
    logSafe("Query Parameters: ${queryParams ?? {}}", level: LogLevel.debug);
    logSafe("Headers: ${_headers(token)}", level: LogLevel.debug);

    try {
      final response = await http
          .get(uri, headers: _headers(token))
          .timeout(extendedTimeout);

      logSafe("Response Status: ${response.statusCode}", level: LogLevel.debug);
      logSafe("Response Body: ${response.body}", level: LogLevel.debug);

      if (response.statusCode == 401 && !hasRetried) {
        logSafe("Unauthorized (401). Attempting token refresh...",
            level: LogLevel.warning);

        if (await AuthService.refreshToken()) {
          logSafe("Token refresh succeeded. Retrying request...",
              level: LogLevel.info);
          return await _getRequest(
            endpoint,
            queryParams: queryParams,
            hasRetried: true,
          );
        }

        logSafe("Token refresh failed. Logging out user.",
            level: LogLevel.error);
        await LocalStorage.logout();
      }

      return response;
    } catch (e) {
      logSafe("HTTP GET Exception: $e", level: LogLevel.error);
      return null;
    }
  }

  static Future<http.Response?> _postRequest(
    String endpoint,
    dynamic body, {
    Duration customTimeout = extendedTimeout,
    bool hasRetried = false,
  }) async {
    String? token = await _getToken();
    if (token == null) return null;

    final uri = Uri.parse("${ApiEndpoints.baseUrl}$endpoint");
    logSafe(
      "POST $uri\nHeaders: ${_headers(token)}\nBody: $body",
    );

    try {
      final response = await http
          .post(uri, headers: _headers(token), body: jsonEncode(body))
          .timeout(customTimeout);

      if (response.statusCode == 401 && !hasRetried) {
        logSafe("Unauthorized POST. Attempting token refresh...");
        if (await AuthService.refreshToken()) {
          return await _postRequest(endpoint, body,
              customTimeout: customTimeout, hasRetried: true);
        }
      }
      return response;
    } catch (e) {
      logSafe("HTTP POST Exception: $e", level: LogLevel.error);
      return null;
    }
  }

  static Future<http.Response?> _putRequest(
    String endpoint,
    dynamic body, {
    Map<String, String>? additionalHeaders,
    Duration customTimeout = extendedTimeout,
    bool hasRetried = false,
  }) async {
    String? token = await _getToken();
    if (token == null) return null;

    final uri = Uri.parse("${ApiEndpoints.baseUrl}$endpoint");
    logSafe(
      "PUT $uri\nHeaders: ${_headers(token)}\nBody: $body",
    );
    final headers = {
      ..._headers(token),
      if (additionalHeaders != null) ...additionalHeaders,
    };

    logSafe(
      "PUT $uri\nHeaders: $headers\nBody: $body",
    );

    try {
      final response = await http
          .put(uri, headers: headers, body: jsonEncode(body))
          .timeout(customTimeout);

      if (response.statusCode == 401 && !hasRetried) {
        logSafe("Unauthorized PUT. Attempting token refresh...");
        if (await AuthService.refreshToken()) {
          return await _putRequest(endpoint, body,
              additionalHeaders: additionalHeaders,
              customTimeout: customTimeout,
              hasRetried: true);
        }
      }

      return response;
    } catch (e) {
      logSafe("HTTP PUT Exception: $e", level: LogLevel.error);
      return null;
    }
  }

  static Future<http.Response?> _deleteRequest(
    String endpoint, {
    Map<String, String>? additionalHeaders,
    Duration customTimeout = extendedTimeout,
    bool hasRetried = false,
  }) async {
    String? token = await _getToken();
    if (token == null) return null;

    final uri = Uri.parse("${ApiEndpoints.baseUrl}$endpoint");
    final headers = {
      ..._headers(token),
      if (additionalHeaders != null) ...additionalHeaders,
    };

    logSafe("DELETE $uri\nHeaders: $headers");

    try {
      final response =
          await http.delete(uri, headers: headers).timeout(customTimeout);

      if (response.statusCode == 401 && !hasRetried) {
        logSafe("Unauthorized DELETE. Attempting token refresh...");
        if (await AuthService.refreshToken()) {
          return await _deleteRequest(
            endpoint,
            additionalHeaders: additionalHeaders,
            customTimeout: customTimeout,
            hasRetried: true,
          );
        }
      }

      return response;
    } catch (e) {
      logSafe("HTTP DELETE Exception: $e", level: LogLevel.error);
      return null;
    }
  }


   /// ============================================
  /// GET PURCHASE INVOICE OVERVIEW (Dashboard)
  /// ============================================
  static Future<PurchaseInvoiceOverviewResponse?> getPurchaseInvoiceOverview({
    String? projectId,
  }) async {
    try {
      final queryParams = <String, String>{};
      if (projectId != null && projectId.isNotEmpty) {
        queryParams['projectId'] = projectId;
      }

      final response = await _getRequest(
        ApiEndpoints.getPurchaseInvoiceOverview,
        queryParams: queryParams,
      );

      if (response == null) {
        _log("getPurchaseInvoiceOverview: No response from server",
            level: LogLevel.error);
        return null;
      }

      final parsedJson = _parseResponseForAllData(
        response,
        label: "PurchaseInvoiceOverview",
      );

      if (parsedJson == null) return null;

      return PurchaseInvoiceOverviewResponse.fromJson(parsedJson);
    } catch (e, stack) {
      _log("Exception in getPurchaseInvoiceOverview: $e\n$stack",
          level: LogLevel.error);
      return null;
    }
  }
  /// ============================================
  /// GET COLLECTION OVERVIEW (Dashboard)
  /// ============================================
  static Future<CollectionOverviewResponse?> getCollectionOverview({
    String? projectId,
  }) async {
    try {
      // Build query params (only add projectId if not null)
      final queryParams = <String, String>{};
      if (projectId != null && projectId.isNotEmpty) {
        queryParams['projectId'] = projectId;
      }

      final response = await _getRequest(
        ApiEndpoints.getCollectionOverview,
        queryParams: queryParams,
      );

      if (response == null) {
        _log("getCollectionOverview: No response from server",
            level: LogLevel.error);
        return null;
      }

      // Parse full JSON (success, message, data, etc.)
      final parsedJson =
          _parseResponseForAllData(response, label: "CollectionOverview");

      if (parsedJson == null) return null;

      return CollectionOverviewResponse.fromJson(parsedJson);
    } catch (e, stack) {
      _log("Exception in getCollectionOverview: $e\n$stack",
          level: LogLevel.error);
      return null;
    }
  }

// Infra Project Module APIs

  /// ================================
  /// GET INFRA PROJECT DETAILS
  /// ================================
  static Future<ProjectDetailsResponse?> getInfraProjectDetails({
    required String projectId,
  }) async {
    final endpoint = "${ApiEndpoints.getInfraProjectDetail}/$projectId";

    try {
      final response = await _getRequest(endpoint);

      if (response == null) {
        _log("getInfraProjectDetails: No response from server",
            level: LogLevel.error);
        return null;
      }

      final parsedJson =
          _parseResponseForAllData(response, label: "InfraProjectDetails");

      if (parsedJson == null) return null;

      return ProjectDetailsResponse.fromJson(parsedJson);
    } catch (e, stack) {
      _log("Exception in getInfraProjectDetails: $e\n$stack",
          level: LogLevel.error);
      return null;
    }
  }

  /// ================================
  /// GET INFRA PROJECTS LIST
  /// ================================
  static Future<ProjectsResponse?> getInfraProjectsList({
    int pageSize = 20,
    int pageNumber = 1,
    String searchString = "",
  }) async {
    final queryParams = {
      "pageSize": pageSize.toString(),
      "pageNumber": pageNumber.toString(),
      "searchString": searchString,
    };

    try {
      final response = await _getRequest(
        ApiEndpoints.getInfraProjectsList,
        queryParams: queryParams,
      );

      if (response == null) {
        _log("getInfraProjectsList: No response from server",
            level: LogLevel.error);
        return null;
      }

      final parsedJson =
          _parseResponseForAllData(response, label: "InfraProjectsList");

      if (parsedJson == null) return null;

      return ProjectsResponse.fromJson(parsedJson);
    } catch (e, stack) {
      _log("Exception in getInfraProjectsList: $e\n$stack",
          level: LogLevel.error);
      return null;
    }
  }

  static Future<JobCommentResponse?> getJobCommentList({
    required String jobTicketId,
    int pageNumber = 1,
    int pageSize = 20,
  }) async {
    final queryParams = {
      'jobTicketId': jobTicketId,
      'pageNumber': pageNumber.toString(),
      'pageSize': pageSize.toString(),
    };

    try {
      final response = await _getRequest(
        ApiEndpoints.getJobCommentList,
        queryParams: queryParams,
      );

      if (response == null) {
        _log("getJobCommentList: No response from server",
            level: LogLevel.error);
        return null;
      }

      final parsedJson =
          _parseResponseForAllData(response, label: "JobCommentList");
      if (parsedJson == null) return null;

      return JobCommentResponse.fromJson(parsedJson);
    } catch (e, stack) {
      _log("Exception in getJobCommentList: $e\n$stack", level: LogLevel.error);
      return null;
    }
  }

  static Future<bool> addJobComment({
    required String jobTicketId,
    required String comment,
    List<Map<String, dynamic>> attachments = const [],
  }) async {
    final body = {
      "jobTicketId": jobTicketId,
      "comment": comment,
      "attachments": attachments,
    };

    try {
      final response = await _postRequest(
        ApiEndpoints.addJobComment,
        body,
      );

      if (response == null) {
        _log("addJobComment: No response from server", level: LogLevel.error);
        return false;
      }

      // Handle 201 Created as success manually
      if (response.statusCode == 201) {
        _log("AddJobComment: Comment added successfully (201).",
            level: LogLevel.info);
        return true;
      }

      // Otherwise fallback to existing _parseResponse
      final parsed = _parseResponse(response, label: "AddJobComment");

      if (parsed != null && parsed['success'] == true) {
        _log("AddJobComment: Comment added successfully.",
            level: LogLevel.info);
        return true;
      } else {
        _log(
          "AddJobComment failed: ${parsed?['message'] ?? 'Unknown error'}",
          level: LogLevel.error,
        );
        return false;
      }
    } catch (e, stack) {
      _log("Exception in addJobComment: $e\n$stack", level: LogLevel.error);
      return false;
    }
  }

  static Future<List<JobStatus>?> getMasterJobStatus({
    required String statusId,
    required String projectId,
  }) async {
    final queryParams = {
      'statusId': statusId,
      'projectId': projectId,
    };

    try {
      final response = await _getRequest(
        ApiEndpoints.getMasterJobStatus,
        queryParams: queryParams,
      );

      if (response == null) {
        _log("getMasterJobStatus: No response received.");
        return null;
      }

      final parsedJson =
          _parseResponseForAllData(response, label: "MasterJobStatus");

      if (parsedJson == null) return null;

      // Directly parse JobStatus list
      final dataList = (parsedJson['data'] as List<dynamic>?)
          ?.map((e) => JobStatus.fromJson(e))
          .toList();

      return dataList;
    } catch (e, stack) {
      _log("Exception in getMasterJobStatus: $e\n$stack",
          level: LogLevel.error);
      return null;
    }
  }

  /// Fetch Service Project Branches with full response
  static Future<ServiceProjectBranchesResponse?> getServiceProjectBranchesFull({
    required String projectId,
    int pageNumber = 1,
    int pageSize = 20,
    String searchString = '',
    bool isActive = true,
  }) async {
    final queryParams = {
      'pageNumber': pageNumber.toString(),
      'pageSize': pageSize.toString(),
      'searchString': searchString,
      'isActive': isActive.toString(),
    };

    final endpoint = "${ApiEndpoints.getServiceProjectBranches}/$projectId";

    try {
      final response = await _getRequest(
        endpoint,
        queryParams: queryParams,
      );

      if (response == null) {
        _log("getServiceProjectBranchesFull: No response received.");
        return null;
      }

      final parsedJson = _parseResponseForAllData(
        response,
        label: "ServiceProjectBranchesFull",
      );

      if (parsedJson == null) return null;

      return ServiceProjectBranchesResponse.fromJson(parsedJson);
    } catch (e, stack) {
      _log(
        "Exception in getServiceProjectBranchesFull: $e\n$stack",
        level: LogLevel.error,
      );
      return null;
    }
  }

  // Service Project Module APIs
  static Future<List<TeamRole>?> getTeamRoles() async {
    try {
      final response = await _getRequest(ApiEndpoints.getTeamRoles);

      if (response == null) {
        _log("getTeamRoles: No response received.");
        return null;
      }

      final parsedJson = _parseResponseForAllData(response, label: "TeamRoles");
      if (parsedJson == null) return null;

      // Map the 'data' array to List<TeamRole>
      final List<dynamic> dataList = parsedJson['data'] as List<dynamic>;
      return dataList
          .map((e) => TeamRole.fromJson(e as Map<String, dynamic>))
          .toList();
    } catch (e, stack) {
      _log("Exception in getTeamRoles: $e\n$stack", level: LogLevel.error);
      return null;
    }
  }

  /// Fetch Service Project Allocation List

  static Future<List<ServiceProjectAllocation>?>
      getServiceProjectAllocationList({
    required String projectId,
    bool isActive = true,
  }) async {
    final queryParams = {
      'projectId': projectId,
      'isActive': isActive.toString(),
    };

    try {
      final response = await _getRequest(
        ApiEndpoints.getServiceProjectUpateJobAllocationList,
        queryParams: queryParams,
      );

      if (response == null) {
        _log("getServiceProjectAllocationList: No response received.");
        return null;
      }

      final parsedJson = _parseResponseForAllData(response,
          label: "ServiceProjectAllocationList");
      if (parsedJson == null) return null;

      final dataList = (parsedJson['data'] as List<dynamic>)
          .map((e) => ServiceProjectAllocation.fromJson(e))
          .toList();

      return dataList;
    } catch (e, stack) {
      _log("Exception in getServiceProjectAllocationList: $e\n$stack");
      return null;
    }
  }

  /// Manage Service Project Allocation
  static Future<bool> manageServiceProjectAllocation({
    required List<Map<String, dynamic>> payload,
  }) async {
    try {
      final response = await _postRequest(
        ApiEndpoints.manageServiceProjectUpateJobAllocation,
        payload,
      );

      if (response == null) {
        _log("manageServiceProjectAllocation: No response received.",
            level: LogLevel.error);
        return false;
      }

      final json = jsonDecode(response.body);
      if (json['success'] == true) {
        _log(
            "Service Project Allocation updated successfully: ${json['data']}");
        return true;
      } else {
        _log(
          "Failed to update Service Project Allocation: ${json['message'] ?? 'Unknown error'}",
          level: LogLevel.warning,
        );
        return false;
      }
    } catch (e, stack) {
      _log("Exception during manageServiceProjectAllocation: $e",
          level: LogLevel.error);
      _log("StackTrace: $stack", level: LogLevel.debug);
      return false;
    }
  }

  static Future<JobAttendanceResponse?> getJobAttendanceLog({
    required String attendanceId,
  }) async {
    final endpoint =
        "${ApiEndpoints.serviceProjectUpateJobAttendanceLog}/$attendanceId";

    try {
      final response = await _getRequest(endpoint);

      if (response == null) {
        _log("getJobAttendanceLog: No response received.");
        return null;
      }

      final parsedJson =
          _parseResponseForAllData(response, label: "JobAttendanceLog");
      if (parsedJson == null) return null;

      return JobAttendanceResponse.fromJson(parsedJson);
    } catch (e, stack) {
      _log("Exception in getJobAttendanceLog: $e\n$stack");
      return null;
    }
  }

  /// Update Service Project Job Attendance
  static Future<bool> updateServiceProjectJobAttendance({
    required Map<String, dynamic> payload,
  }) async {
    const endpoint = ApiEndpoints.serviceProjectUpateJobAttendance;

    logSafe("Updating Service Project Job Attendance with payload: $payload");

    try {
      final response = await _postRequest(endpoint, payload);

      if (response == null) {
        logSafe("Update Job Attendance failed: null response",
            level: LogLevel.error);
        return false;
      }

      logSafe("Update Job Attendance response status: ${response.statusCode}");
      logSafe("Update Job Attendance response body: ${response.body}");

      final json = jsonDecode(response.body);
      if (json['success'] == true) {
        logSafe("Job Attendance updated successfully: ${json['data']}");
        return true;
      } else {
        logSafe(
          "Failed to update Job Attendance: ${json['message'] ?? 'Unknown error'}",
          level: LogLevel.warning,
        );
        return false;
      }
    } catch (e, stack) {
      logSafe("Exception during updateServiceProjectJobAttendance: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
      return false;
    }
  }

  /// Edit a Service Project Job
  static Future<bool> editServiceProjectJobApi({
    required String jobId,
    required List<Map<String, dynamic>> operations,
  }) async {
    final endpoint = "${ApiEndpoints.editServiceProjectJob}/$jobId";

    logSafe("Editing Service Project Job: $jobId with operations: $operations");

    try {
      // PATCH request is usually similar to PUT, but with http.patch
      String? token = await _getToken();
      if (token == null) return false;

      final uri = Uri.parse("${ApiEndpoints.baseUrl}$endpoint");

      final headers = _headers(token);

      final response = await http
          .patch(uri, headers: headers, body: jsonEncode(operations))
          .timeout(extendedTimeout);

      logSafe(
          "Edit Service Project Job response status: ${response.statusCode}");
      logSafe("Edit Service Project Job response body: ${response.body}");

      final json = jsonDecode(response.body);

      if (response.statusCode == 200 && json['success'] == true) {
        logSafe("Service Project Job edited successfully: ${json['data']}");
        return true;
      } else {
        logSafe(
          "Failed to edit Service Project Job: ${json['message'] ?? 'Unknown error'}",
          level: LogLevel.warning,
        );
        return false;
      }
    } catch (e, stack) {
      logSafe("Exception during editServiceProjectJobApi: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
      return false;
    }
  }

  /// Get details for a single Service Project Job
  static Future<JobDetailsResponse?> getServiceProjectJobDetailApi(
      String jobId) async {
    final endpoint = "${ApiEndpoints.getServiceProjectJobDetail}/$jobId";
    logSafe("Fetching Job Detail for Job ID: $jobId");

    try {
      final response = await _getRequest(endpoint);
      if (response == null) {
        logSafe("Service Project Job Detail request failed: null response",
            level: LogLevel.error);
        return null;
      }

      final jsonResponse = _parseResponseForAllData(
        response,
        label: "Service Project Job Detail",
      );

      if (jsonResponse != null) {
        return JobDetailsResponse.fromJson(jsonResponse);
      }
    } catch (e, stack) {
      logSafe("Exception during getServiceProjectJobDetailApi: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return null;
  }

  static Future<String?> createServiceProjectJobApi({
    required String title,
    required String description,
    required String projectId,
    required List<Map<String, dynamic>> assignees,
    required DateTime startDate,
    required DateTime dueDate,
    required List<Map<String, dynamic>> tags,
    required String? branchId,
  }) async {
    const endpoint = ApiEndpoints.createServiceProjectJob;
    logSafe("Creating Service Project Job for projectId: $projectId");

    final body = {
      "title": title,
      "description": description,
      "projectId": projectId,
      "assignees": assignees,
      "startDate": startDate.toIso8601String(),
      "dueDate": dueDate.toIso8601String(),
      "tags": tags,
      "projectBranchId": branchId,
    };

    try {
      final response = await _postRequest(endpoint, body);

      if (response == null) return null;

      final json = jsonDecode(response.body);

      if (json['success'] == true) {
        final jobId = json['data']?['id'];
        logSafe("Service Project Job created successfully: $jobId");
        return jobId;
      }

      return null;
    } catch (e, stack) {
      logSafe("Exception during createServiceProjectJobApi: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
      return null;
    }
  }

  /// Get Service Project Job List (Active or Archived)
  static Future<JobResponse?> getServiceProjectJobListApi({
    required String projectId,
    int pageNumber = 1,
    int pageSize = 20,
    bool isActive = true,
    bool isArchive = false, // new parameter to fetch archived jobs
  }) async {
    const endpoint = ApiEndpoints.getServiceProjectJobList;
    logSafe(
      "Fetching Job List for Service Project: $projectId | isActive: $isActive | isArchive: $isArchive",
    );

    try {
      final queryParams = {
        'projectId': projectId,
        'pageNumber': pageNumber.toString(),
        'pageSize': pageSize.toString(),
        'isActive': isActive.toString(),
        if (isArchive) 'isArchive': 'true',
      };

      final response = await _getRequest(endpoint, queryParams: queryParams);

      if (response == null) {
        logSafe(
          "Service Project Job List request failed: null response",
          level: LogLevel.error,
        );
        return null;
      }

      final jsonResponse = _parseResponseForAllData(
        response,
        label: isArchive
            ? "Archived Service Project Job List"
            : "Active Service Project Job List",
      );

      if (jsonResponse != null) {
        return JobResponse.fromJson(jsonResponse);
      }
    } catch (e, stack) {
      logSafe(
        "Exception during getServiceProjectJobListApi: $e",
        level: LogLevel.error,
      );
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return null;
  }

// API to get all employees from basic
  static Future<List<dynamic>?> allEmployeesBasic({
    bool allEmployee = true,
  }) async {
    final queryParams = <String, String>{};

    // Always include allEmployee parameter
    queryParams['allEmployee'] = allEmployee.toString();

    final response = await _getRequest(
      ApiEndpoints.getEmployeesWithoutPermission,
      queryParams: queryParams,
    );

    if (response != null) {
      return _parseResponse(response, label: ' All Employees Basic');
    }

    return null;
  }

  /// Get details of a single service project
  static Future<ServiceProjectDetailModel?> getServiceProjectDetailApi(
      String projectId) async {
    final endpoint = "${ApiEndpoints.getServiceProjectDetail}/$projectId";
    logSafe("Fetching details for Service Project ID: $projectId");

    try {
      final response = await _getRequest(endpoint);

      if (response == null) {
        logSafe(
          "Service Project Detail request failed: null response",
          level: LogLevel.error,
        );
        return null;
      }

      final jsonResponse = _parseResponseForAllData(
        response,
        label: "Service Project Detail",
      );

      if (jsonResponse != null) {
        return ServiceProjectDetailModel.fromJson(jsonResponse);
      }
    } catch (e, stack) {
      logSafe(
        "Exception during getServiceProjectDetailApi: $e",
        level: LogLevel.error,
      );
      logSafe(
        "StackTrace: $stack",
        level: LogLevel.debug,
      );
    }

    return null;
  }

  /// Get Service Project List
  static Future<ServiceProjectListModel?> getServiceProjectsListApi({
    int pageNumber = 1,
    int pageSize = 20,
  }) async {
    const endpoint = ApiEndpoints.getServiceProjectsList;
    logSafe("Fetching Service Project List");

    try {
      final queryParams = {
        'pageNumber': pageNumber.toString(),
        'pageSize': pageSize.toString(),
      };

      final response = await _getRequest(endpoint, queryParams: queryParams);

      if (response == null) {
        logSafe("Service Project List request failed: null response",
            level: LogLevel.error);
        return null;
      }

      final jsonResponse = _parseResponseForAllData(
        response,
        label: "Service Project List",
      );

      if (jsonResponse != null) {
        return ServiceProjectListModel.fromJson(jsonResponse);
      }
    } catch (e, stack) {
      logSafe("Exception during getServiceProjectsListApi: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return null;
  }

  /// Edit Expense Payment Request
  static Future<bool> editExpensePaymentRequestApi({
    required String id,
    required String title,
    required String description,
    required String payee,
    required String currencyId,
    required double amount,
    required String dueDate,
    required String projectId,
    required String expenseCategoryId,
    required bool isAdvancePayment,
    List<Map<String, dynamic>> billAttachments = const [],
  }) async {
    final endpoint = "${ApiEndpoints.getExpensePaymentRequestEdit}/$id";

    final body = {
      "id": id,
      "title": title,
      "description": description,
      "payee": payee,
      "currencyId": currencyId,
      "amount": amount,
      "dueDate": dueDate,
      "projectId": projectId,
      "expenseCategoryId": expenseCategoryId,
      "isAdvancePayment": isAdvancePayment,
      "billAttachments": billAttachments,
    };

    try {
      final response = await _putRequest(endpoint, body);

      if (response == null) {
        logSafe("Edit Expense Payment Request failed: null response",
            level: LogLevel.error);
        return false;
      }

      logSafe(
          "Edit Expense Payment Request response status: ${response.statusCode}");
      logSafe("Edit Expense Payment Request response body: ${response.body}");

      final json = jsonDecode(response.body);
      if (json['success'] == true) {
        logSafe(
            "Expense Payment Request edited successfully: ${json['data'] ?? 'No data'}");
        return true;
      } else {
        logSafe(
          "Failed to edit Expense Payment Request: ${json['message'] ?? 'Unknown error'}",
          level: LogLevel.warning,
        );
        return false;
      }
    } catch (e, stack) {
      logSafe("Exception during editExpensePaymentRequestApi: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
      return false;
    }
  }

  /// Create Expense for Payment Request
  static Future<bool> createExpenseForPRApi({
    required String paymentModeId,
    required String location,
    required String gstNumber,
    required String statusId,
    required String paymentRequestId,
    required String comment,
    List<Map<String, dynamic>> billAttachments = const [],
  }) async {
    const endpoint = ApiEndpoints.createExpenseforPR;

    final body = {
      "paymentModeId": paymentModeId,
      "location": location,
      "gstNumber": gstNumber,
      "statusId": statusId,
      "comment": comment,
      "paymentRequestId": paymentRequestId,
      "billAttachments": billAttachments,
    };

    try {
      final response = await _postRequest(endpoint, body);

      if (response == null) {
        logSafe("Create Expense for PR failed: null response",
            level: LogLevel.error);
        return false;
      }

      logSafe("Create Expense for PR response status: ${response.statusCode}");
      logSafe("Create Expense for PR response body: ${response.body}");

      final json = jsonDecode(response.body);
      if (json['success'] == true) {
        logSafe(
            "Expense for Payment Request created successfully: ${json['data']}");
        return true;
      } else {
        logSafe(
          "Failed to create Expense for Payment Request: ${json['message'] ?? 'Unknown error'}",
          level: LogLevel.warning,
        );
        return false;
      }
    } catch (e, stack) {
      logSafe("Exception during createExpenseForPRApi: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
      return false;
    }
  }

  /// Update Expense Payment Request Status
  static Future<bool> updateExpensePaymentRequestStatusApi({
    required String paymentRequestId,
    required String statusId,
    required String comment,
    String? paidTransactionId,
    String? paidById,
    DateTime? paidAt,
    double? baseAmount,
    double? taxAmount,
    String? tdsPercentage,
  }) async {
    const endpoint = ApiEndpoints.updateExpensePaymentRequestStatus;
    logSafe("Updating Payment Request Status for ID: $paymentRequestId");

    final body = {
      "paymentRequestId": paymentRequestId,
      "statusId": statusId,
      "comment": comment,
      "paidTransactionId": paidTransactionId,
      "paidById": paidById,
      "paidAt": paidAt?.toIso8601String(),
      "baseAmount": baseAmount,
      "taxAmount": taxAmount,
      "tdsPercentage": tdsPercentage ?? "0",
    };

    try {
      final response = await _postRequest(endpoint, body);

      if (response == null) {
        logSafe("Update Payment Request Status failed: null response",
            level: LogLevel.error);
        return false;
      }

      logSafe(
          "Update Payment Request Status response: ${response.statusCode} -> ${response.body}");

      final json = jsonDecode(response.body);
      if (json['success'] == true) {
        logSafe("Payment Request status updated successfully!");
        return true;
      } else {
        logSafe(
          "Failed to update Payment Request Status: ${json['message'] ?? 'Unknown error'}",
          level: LogLevel.warning,
        );
        return false;
      }
    } catch (e, stack) {
      logSafe("Exception during updateExpensePaymentRequestStatusApi: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
      return false;
    }
  }

  /// Get Expense Payment Request Detail by ID
  static Future<PaymentRequestDetail?> getExpensePaymentRequestDetailApi(
      String paymentRequestId) async {
    final endpoint =
        "${ApiEndpoints.getExpensePaymentRequestDetails}/$paymentRequestId";
    logSafe(
        "Fetching Expense Payment Request Detail for ID: $paymentRequestId");

    try {
      final response = await _getRequest(endpoint);

      if (response == null) {
        logSafe("Expense Payment Request Detail request failed: null response",
            level: LogLevel.error);
        return null;
      }

      final jsonResponse = _parseResponseForAllData(
        response,
        label: "Expense Payment Request Detail",
      );

      if (jsonResponse != null) {
        return PaymentRequestDetail.fromJson(jsonResponse);
      }
    } catch (e, stack) {
      logSafe("Exception during getExpensePaymentRequestDetailApi: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return null;
  }

  static Future<PaymentRequestFilter?>
      getExpensePaymentRequestFilterApi() async {
    const endpoint = ApiEndpoints.getExpensePaymentRequestFilter;
    logSafe("Fetching Expense Payment Request Filter");

    try {
      final response = await _getRequest(endpoint);

      if (response == null) {
        logSafe("Expense Payment Request Filter request failed: null response",
            level: LogLevel.error);
        return null;
      }

      final jsonResponse = _parseResponseForAllData(
        response,
        label: "Expense Payment Request Filter",
      );

      if (jsonResponse != null) {
        return PaymentRequestFilter.fromJson(jsonResponse);
      }
    } catch (e, stack) {
      logSafe("Exception during getExpensePaymentRequestFilterApi: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return null;
  }

  /// Get Expense Payment Request List
  static Future<PaymentRequestResponse?> getExpensePaymentRequestListApi({
    bool isActive = true,
    int pageSize = 20,
    int pageNumber = 1,
    Map<String, dynamic>? filter,
    String searchString = '',
  }) async {
    const endpoint = ApiEndpoints.getExpensePaymentRequestList;
    logSafe("Fetching Expense Payment Request List");

    try {
      final queryParams = {
        'isActive': isActive.toString(),
        'pageSize': pageSize.toString(),
        'pageNumber': pageNumber.toString(),
        'filter': jsonEncode(filter ??
            {
              "projectIds": [],
              "statusIds": [],
              "createdByIds": [],
              "currencyIds": [],
              "expenseCategoryIds": [],
              "payees": [],
              "startDate": null,
              "endDate": null
            }),
        'searchString': searchString,
      };

      final response = await _getRequest(endpoint, queryParams: queryParams);

      if (response == null) {
        logSafe("Expense Payment Request List request failed: null response",
            level: LogLevel.error);
        return null;
      }

      final jsonResponse = _parseResponseForAllData(
        response,
        label: "Expense Payment Request List",
      );

      if (jsonResponse != null) {
        return PaymentRequestResponse.fromJson(jsonResponse);
      }
    } catch (e, stack) {
      logSafe("Exception during getExpensePaymentRequestListApi: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return null;
  }

  /// Create Expense Payment Request (Project API style)
  static Future<bool> createExpensePaymentRequestApi({
    required String title,
    required String projectId,
    required String expenseCategoryId,
    required String currencyId,
    required String payee,
    required double amount,
    DateTime? dueDate,
    required String description,
    required bool isAdvancePayment,
    List<Map<String, dynamic>> billAttachments = const [],
  }) async {
    const endpoint = ApiEndpoints.createExpensePaymentRequest;

    final body = {
      "title": title,
      "projectId": projectId,
      "expenseCategoryId": expenseCategoryId,
      "currencyId": currencyId,
      "payee": payee,
      "amount": amount,
      "dueDate": dueDate?.toIso8601String(),
      "description": description,
      "isAdvancePayment": isAdvancePayment,
      "billAttachments": billAttachments,
    };

    try {
      final response = await _postRequest(endpoint, body);
      if (response == null) {
        logSafe("Create Payment Request failed: null response",
            level: LogLevel.error);
        return false;
      }

      logSafe("Create Payment Request response status: ${response.statusCode}");
      logSafe("Create Payment Request response body: ${response.body}");

      final json = jsonDecode(response.body);
      if (json['success'] == true) {
        logSafe("Payment Request created successfully: ${json['data']}");
        return true;
      } else {
        logSafe(
          "Failed to create Payment Request: ${json['message'] ?? 'Unknown error'}",
          level: LogLevel.warning,
        );
        return false;
      }
    } catch (e, stack) {
      logSafe("Exception during createExpensePaymentRequestApi: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
      return false;
    }
  }

  /// Fetch hierarchy list for an employee
  static Future<List<dynamic>?> getOrganizationHierarchyList(
      String employeeId) async {
    if (employeeId.isEmpty) throw ArgumentError('employeeId must not be empty');
    final endpoint = "${ApiEndpoints.getOrganizationHierarchyList}/$employeeId";

    return _getRequest(endpoint).then(
      (res) => res != null
          ? _parseResponse(res, label: 'Organization Hierarchy List')
          : null,
    );
  }

  /// Manage (create/update) organization hierarchy (assign reporters) for an employee
  /// payload is a List<Map<String,dynamic>> with objects like:
  /// { "reportToId": "<uuid>", "isPrimary": true, "isActive": true }
  static Future<bool> manageOrganizationHierarchy({
    required String employeeId,
    required List<Map<String, dynamic>> payload,
  }) async {
    if (employeeId.isEmpty) throw ArgumentError('employeeId must not be empty');

    final endpoint = "${ApiEndpoints.manageOrganizationHierarchy}/$employeeId";

    logSafe("manageOrganizationHierarchy for $employeeId payload: $payload");

    try {
      final response = await _postRequest(endpoint, payload);
      if (response == null) {
        logSafe("Manage hierarchy failed: null response",
            level: LogLevel.error);
        return false;
      }

      logSafe("Manage hierarchy response status: ${response.statusCode}");
      logSafe("Manage hierarchy response body: ${response.body}");

      final json = jsonDecode(response.body);
      if (json['success'] == true) {
        logSafe("Manage hierarchy succeeded");
        return true;
      }

      logSafe("Manage hierarchy failed: ${json['message'] ?? 'Unknown error'}",
          level: LogLevel.error);
      return false;
    } catch (e, stack) {
      logSafe("Exception while manageOrganizationHierarchy: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
      return false;
    }
  }

  /// Get Master Currencies
  static Future<CurrencyListResponse?> getMasterCurrenciesApi() async {
    const endpoint = ApiEndpoints.getMasterCurrencies;
    logSafe("Fetching Master Currencies");

    try {
      final response = await _getRequest(endpoint);

      if (response == null) {
        logSafe("Master Currencies request failed: null response",
            level: LogLevel.error);
        return null;
      }

      final jsonResponse =
          _parseResponseForAllData(response, label: "Master Currencies");
      if (jsonResponse != null) {
        return CurrencyListResponse.fromJson(jsonResponse);
      }
    } catch (e, stack) {
      logSafe("Exception during getMasterCurrenciesApi: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return null;
  }

  /// Get Master Expense Categories
  static Future<ExpenseCategoryResponse?>
      getMasterExpenseCategoriesApi() async {
    const endpoint = ApiEndpoints.getMasterExpensesCategories;
    logSafe("Fetching Master Expense Categories");

    try {
      final response = await _getRequest(endpoint);

      if (response == null) {
        logSafe("Master Expense Categories request failed: null response",
            level: LogLevel.error);
        return null;
      }

      final jsonResponse = _parseResponseForAllData(response,
          label: "Master Expense Categories");
      if (jsonResponse != null) {
        return ExpenseCategoryResponse.fromJson(jsonResponse);
      }
    } catch (e, stack) {
      logSafe("Exception during getMasterExpenseCategoriesApi: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return null;
  }

  /// Get Expense Payment Request Payee
  static Future<PaymentRequestPayeeResponse?>
      getExpensePaymentRequestPayeeApi() async {
    const endpoint = ApiEndpoints.getExpensePaymentRequestPayee;
    logSafe("Fetching Expense Payment Request Payees");

    try {
      final response = await _getRequest(endpoint);

      if (response == null) {
        logSafe("Expense Payment Request Payee request failed: null response",
            level: LogLevel.error);
        return null;
      }

      final jsonResponse = _parseResponseForAllData(response,
          label: "Expense Payment Request Payee");
      if (jsonResponse != null) {
        return PaymentRequestPayeeResponse.fromJson(jsonResponse);
      }
    } catch (e, stack) {
      logSafe("Exception during getExpensePaymentRequestPayeeApi: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return null;
  }

  /// Get Monthly Expense Report (categoryId is optional)
  static Future<DashboardMonthlyExpenseResponse?>
      getDashboardMonthlyExpensesApi({
    String? categoryId,
    int months = 12,
  }) async {
    const endpoint = ApiEndpoints.getDashboardMonthlyExpenses;
    logSafe("Fetching Dashboard Monthly Expenses for last $months months");

    try {
      final queryParams = {
        'months': months.toString(),
        if (categoryId != null && categoryId.isNotEmpty)
          'categoryId': categoryId,
      };

      final response = await _getRequest(
        endpoint,
        queryParams: queryParams,
      );

      if (response == null) {
        logSafe("Monthly Expense request failed: null response",
            level: LogLevel.error);
        return null;
      }

      final jsonResponse = _parseResponseForAllData(response,
          label: "Dashboard Monthly Expenses");

      if (jsonResponse != null) {
        return DashboardMonthlyExpenseResponse.fromJson(jsonResponse);
      }
    } catch (e, stack) {
      logSafe("Exception during getDashboardMonthlyExpensesApi: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return null;
  }

  /// Get Expense Category Report
  static Future<ExpenseTypeReportResponse?> getExpenseTypeReportApi({
    required String projectId,
    required DateTime startDate,
    required DateTime endDate,
  }) async {
    const endpoint = ApiEndpoints.getExpenseTypeReport;
    logSafe("Fetching Expense Category Report for projectId: $projectId");

    try {
      final response = await _getRequest(
        endpoint,
        queryParams: {
          'projectId': projectId,
          'startDate': startDate.toIso8601String(),
          'endDate': endDate.toIso8601String(),
        },
      );

      if (response == null) {
        logSafe("Expense Category Report request failed: null response",
            level: LogLevel.error);
        return null;
      }

      final jsonResponse =
          _parseResponseForAllData(response, label: "Expense Category Report");

      if (jsonResponse != null) {
        return ExpenseTypeReportResponse.fromJson(jsonResponse);
      }
    } catch (e, stack) {
      logSafe("Exception during getExpenseTypeReportApi: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return null;
  }

  /// Get Pending Expenses
  static Future<PendingExpensesResponse?> getPendingExpensesApi({
    required String projectId,
  }) async {
    const endpoint = ApiEndpoints.getPendingExpenses;
    logSafe("Fetching Pending Expenses for projectId: $projectId");

    try {
      final response = await _getRequest(
        endpoint,
        queryParams: {'projectId': projectId},
      );

      if (response == null) {
        logSafe("Pending Expenses request failed: null response",
            level: LogLevel.error);
        return null;
      }

      final jsonResponse =
          _parseResponseForAllData(response, label: "Pending Expenses");

      if (jsonResponse != null) {
        return PendingExpensesResponse.fromJson(jsonResponse);
      }
    } catch (e, stack) {
      logSafe("Exception during getPendingExpensesApi: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return null;
  }

  /// Create Project API
  static Future<bool> createProjectApi({
    required String name,
    required String projectAddress,
    required String shortName,
    required String contactPerson,
    required DateTime startDate,
    required DateTime endDate,
    required String projectStatusId,
  }) async {
    const endpoint = ApiEndpoints.createProject;
    logSafe("Creating project: $name");

    final Map<String, dynamic> payload = {
      "name": name,
      "projectAddress": projectAddress,
      "shortName": shortName,
      "contactPerson": contactPerson,
      "startDate": startDate.toIso8601String(),
      "endDate": endDate.toIso8601String(),
      "projectStatusId": projectStatusId,
    };

    try {
      final response =
          await _postRequest(endpoint, payload, customTimeout: extendedTimeout);

      if (response == null) {
        logSafe("Create project failed: null response", level: LogLevel.error);
        return false;
      }

      logSafe("Create project response status: ${response.statusCode}");
      logSafe("Create project response body: ${response.body}");

      final json = jsonDecode(response.body);
      if (json['success'] == true) {
        logSafe("Project created successfully: ${json['data']}");
        return true;
      } else {
        logSafe(
          "Failed to create project: ${json['message'] ?? 'Unknown error'}",
          level: LogLevel.warning,
        );
      }
    } catch (e, stack) {
      logSafe("Exception during createProjectApi: $e", level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return false;
  }

  /// Get Organizations assigned to a Project
  static Future<OrganizationListResponse?> getAssignedOrganizations(
      String projectId) async {
    final endpoint = "${ApiEndpoints.getAssignedOrganizations}/$projectId";
    logSafe("Fetching organizations assigned to projectId: $projectId");

    try {
      final response = await _getRequest(endpoint);

      if (response == null) {
        logSafe("Assigned Organizations request failed: null response",
            level: LogLevel.error);
        return null;
      }

      final jsonResponse =
          _parseResponseForAllData(response, label: "Assigned Organizations");

      if (jsonResponse != null) {
        return OrganizationListResponse.fromJson(jsonResponse);
      }
    } catch (e, stack) {
      logSafe("Exception during getAssignedOrganizations: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return null;
  }

  static Future<AllOrganizationListResponse?> getAllOrganizations() async {
    final endpoint = "${ApiEndpoints.getAllOrganizations}";
    try {
      final response = await _getRequest(endpoint);

      if (response == null) {
        logSafe("All Organizations request failed: null response",
            level: LogLevel.error);
        return null;
      }

      final jsonResponse =
          _parseResponseForAllData(response, label: "All Organizations");

      if (jsonResponse != null) {
        return AllOrganizationListResponse.fromJson(jsonResponse);
      }
    } catch (e, stack) {
      logSafe("Exception during getAllOrganizations: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return null;
  }

  //// Get Services assigned to a Project
  static Future<ServiceListResponse?> getAssignedServices(
      String projectId) async {
    final endpoint = "${ApiEndpoints.getAssignedServices}/$projectId";
    logSafe("Fetching services assigned to projectId: $projectId");

    try {
      final response = await _getRequest(endpoint);

      if (response == null) {
        logSafe("Assigned Services request failed: null response",
            level: LogLevel.error);
        return null;
      }

      final jsonResponse =
          _parseResponseForAllData(response, label: "Assigned Services");

      if (jsonResponse != null) {
        return ServiceListResponse.fromJson(jsonResponse);
      }
    } catch (e, stack) {
      logSafe("Exception during getAssignedServices: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return null;
  }

  static Future<bool> postLogsApi(List<Map<String, dynamic>> logs) async {
    const endpoint = "${ApiEndpoints.uploadLogs}";
    logSafe("Posting logs... count=${logs.length}");

    try {
      // Get token directly without triggering logout or refresh
      final token = await LocalStorage.getJwtToken();
      if (token == null) {
        logSafe("No token available. Skipping logs post.",
            level: LogLevel.warning);
        return false;
      }

      final uri = Uri.parse("${ApiEndpoints.baseUrl}$endpoint");
      final headers = {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer $token',
      };

      final response = await http
          .post(uri, headers: headers, body: jsonEncode(logs))
          .timeout(ApiService.extendedTimeout);

      logSafe("Post logs response status: ${response.statusCode}");
      logSafe("Post logs response body: ${response.body}");

      if (response.statusCode == 200 && response.body.isNotEmpty) {
        final json = jsonDecode(response.body);
        if (json['success'] == true) {
          logSafe("Logs posted successfully.");
          return true;
        }
      }

      logSafe("Failed to post logs: ${response.body}", level: LogLevel.warning);
    } catch (e, stack) {
      logSafe("Exception during postLogsApi: $e", level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return false;
  }

  /// Verify Document API
  static Future<bool> verifyDocumentApi({
    required String id,
    bool isVerify = true,
  }) async {
    final endpoint = "${ApiEndpoints.verifyDocument}/$id";
    final queryParams = {"isVerify": isVerify.toString()};
    logSafe("Verifying document with id: $id | isVerify: $isVerify");

    try {
      final uri = Uri.parse("${ApiEndpoints.baseUrl}$endpoint")
          .replace(queryParameters: queryParams);

      String? token = await _getToken();
      if (token == null) return false;

      final headers = _headers(token);
      logSafe("POST (verify) $uri\nHeaders: $headers");

      final response =
          await http.post(uri, headers: headers).timeout(extendedTimeout);

      if (response.statusCode == 401) {
        logSafe("Unauthorized VERIFY. Attempting token refresh...");
        if (await AuthService.refreshToken()) {
          return await verifyDocumentApi(id: id, isVerify: isVerify);
        }
      }

      logSafe("Verify document response status: ${response.statusCode}");
      logSafe("Verify document response body: ${response.body}");

      final json = jsonDecode(response.body);
      if (json['success'] == true) {
        logSafe("Document verify success: ${json['data']}");
        return true;
      } else {
        logSafe(
          "Failed to verify document: ${json['message'] ?? 'Unknown error'}",
          level: LogLevel.warning,
        );
      }
    } catch (e, stack) {
      logSafe("Exception during verifyDocumentApi: $e", level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return false;
  }

  /// Get Pre-Signed URL for Old Version
  static Future<String?> getPresignedUrlApi(String versionId) async {
    final endpoint = "${ApiEndpoints.getDocumentVersion}/$versionId";
    logSafe("Fetching Pre-Signed URL for versionId: $versionId");

    try {
      final response = await _getRequest(endpoint);

      if (response == null) {
        logSafe("Pre-Signed URL request failed: null response",
            level: LogLevel.error);
        return null;
      }

      final jsonResponse =
          _parseResponseForAllData(response, label: "Pre-Signed URL");

      if (jsonResponse != null) {
        return jsonResponse['data'] as String?;
      }
    } catch (e, stack) {
      logSafe("Exception during getPresignedUrlApi: $e", level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return null;
  }

  /// Delete (Soft Delete / Deactivate) Document API
  static Future<bool> deleteDocumentApi({
    required String id,
    bool isActive = false, // default false = delete
  }) async {
    final endpoint = "${ApiEndpoints.deleteDocument}/$id";
    final queryParams = {"isActive": isActive.toString()};
    logSafe("Deleting document with id: $id | isActive: $isActive");

    try {
      final uri = Uri.parse("${ApiEndpoints.baseUrl}$endpoint")
          .replace(queryParameters: queryParams);

      String? token = await _getToken();
      if (token == null) return false;

      final headers = _headers(token);
      logSafe("DELETE (PUT/POST style) $uri\nHeaders: $headers");

      // some backends use PUT instead of DELETE for soft deletes
      final response =
          await http.delete(uri, headers: headers).timeout(extendedTimeout);

      if (response.statusCode == 401) {
        logSafe("Unauthorized DELETE. Attempting token refresh...");
        if (await AuthService.refreshToken()) {
          return await deleteDocumentApi(id: id, isActive: isActive);
        }
      }

      logSafe("Delete document response status: ${response.statusCode}");
      logSafe("Delete document response body: ${response.body}");

      final json = jsonDecode(response.body);
      if (json['success'] == true) {
        logSafe("Document delete/update success: ${json['data']}");
        return true;
      } else {
        logSafe(
          "Failed to delete document: ${json['message'] ?? 'Unknown error'}",
          level: LogLevel.warning,
        );
      }
    } catch (e, stack) {
      logSafe("Exception during deleteDocumentApi: $e", level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return false;
  }

  /// Edit Document API
  static Future<bool> editDocumentApi({
    required String id,
    required String name,
    required String documentId,
    String? description,
    List<Map<String, dynamic>> tags = const [],
    Map<String, dynamic>? attachment, // 👈 can be null
  }) async {
    final endpoint = "${ApiEndpoints.editDocument}/$id";
    logSafe("Editing document with id: $id");

    final Map<String, dynamic> payload = {
      "id": id,
      "name": name,
      "documentId": documentId,
      "description": description ?? "",
      "tags": tags.isNotEmpty
          ? tags
          : [
              {"name": "default", "isActive": true}
            ],
      "attachment": attachment, // 👈 null or object
    };

    try {
      final response =
          await _putRequest(endpoint, payload, customTimeout: extendedTimeout);

      if (response == null) {
        logSafe("Edit document failed: null response", level: LogLevel.error);
        return false;
      }

      logSafe("Edit document response status: ${response.statusCode}");
      logSafe("Edit document response body: ${response.body}");

      final json = jsonDecode(response.body);
      if (json['success'] == true) {
        logSafe("Document edited successfully: ${json['data']}");
        return true;
      } else {
        logSafe(
          "Failed to edit document: ${json['message'] ?? 'Unknown error'}",
          level: LogLevel.warning,
        );
      }
    } catch (e, stack) {
      logSafe("Exception during editDocumentApi: $e", level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return false;
  }

  /// Get List of Versions by ParentAttachmentId
  static Future<DocumentVersionsResponse?> getDocumentVersionsApi({
    required String parentAttachmentId,
    int pageNumber = 1,
    int pageSize = 20,
  }) async {
    final endpoint = "${ApiEndpoints.getDocumentVersions}/$parentAttachmentId";
    final queryParams = {
      "pageNumber": pageNumber.toString(),
      "pageSize": pageSize.toString(),
    };

    logSafe(
        "Fetching document versions for parentAttachmentId: $parentAttachmentId");

    try {
      final response = await _getRequest(endpoint, queryParams: queryParams);

      if (response == null) {
        logSafe("Document versions request failed: null response",
            level: LogLevel.error);
        return null;
      }

      final jsonResponse =
          _parseResponseForAllData(response, label: "Document Versions");

      if (jsonResponse != null) {
        return DocumentVersionsResponse.fromJson(jsonResponse);
      }
    } catch (e, stack) {
      logSafe("Exception during getDocumentVersionsApi: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return null;
  }

  /// Get Document Details by ID
  static Future<DocumentDetailsResponse?> getDocumentDetailsApi(
      String documentId) async {
    final endpoint = "${ApiEndpoints.getDocumentDetails}/$documentId";
    logSafe("Fetching document details for id: $documentId");

    try {
      final response = await _getRequest(endpoint);

      if (response == null) {
        logSafe("Document details request failed: null response",
            level: LogLevel.error);
        return null;
      }

      final jsonResponse =
          _parseResponseForAllData(response, label: "Document Details");

      if (jsonResponse != null) {
        return DocumentDetailsResponse.fromJson(jsonResponse);
      }
    } catch (e, stack) {
      logSafe("Exception during getDocumentDetailsApi: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return null;
  }

  /// Get Document Types by CategoryId
  static Future<DocumentTypesResponse?> getDocumentTypesByCategoryApi(
      String documentCategoryId) async {
    const endpoint = ApiEndpoints.getDocumentTypesByCategory;

    logSafe("Fetching document types for category: $documentCategoryId");

    try {
      final response = await _getRequest(
        endpoint,
        queryParams: {"documentCategoryId": documentCategoryId},
      );

      if (response == null) {
        logSafe("Document types by category request failed: null response",
            level: LogLevel.error);
        return null;
      }

      final jsonResponse = _parseResponseForAllData(response,
          label: "Document Types by Category");

      if (jsonResponse != null) {
        return DocumentTypesResponse.fromJson(jsonResponse);
      }
    } catch (e, stack) {
      logSafe("Exception during getDocumentTypesByCategoryApi: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return null;
  }

  /// Get Master Document Types (Category Types)
  static Future<DocumentTypesResponse?> getMasterDocumentTypesApi() async {
    const endpoint = ApiEndpoints.getMasterDocumentCategories;
    logSafe("Fetching master document types...");

    try {
      final response = await _getRequest(endpoint);

      if (response == null) {
        logSafe("Document types request failed: null response",
            level: LogLevel.error);
        return null;
      }

      final jsonResponse =
          _parseResponseForAllData(response, label: "Master Document Types");

      if (jsonResponse != null) {
        return DocumentTypesResponse.fromJson(jsonResponse);
      }
    } catch (e, stack) {
      logSafe("Exception during getMasterDocumentTypesApi: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return null;
  }

  /// Upload Document API
  static Future<bool> uploadDocumentApi({
    required String name,
    String? documentId,
    String? description,
    required String entityId,
    required String documentTypeId,
    required String fileName,
    required String base64Data,
    required String contentType,
    required int fileSize,
    String? fileDescription,
    bool isActive = true,
    List<Map<String, dynamic>> tags = const [],
  }) async {
    const endpoint = ApiEndpoints.uploadDocument;
    logSafe("Uploading document: $name for entity: $entityId");

    final Map<String, dynamic> payload = {
      "name": name,
      "documentId": documentId ?? "",
      "description": description ?? "",
      "entityId": entityId,
      "documentTypeId": documentTypeId,
      "attachment": {
        "fileName": fileName,
        "base64Data": base64Data,
        "contentType": contentType,
        "fileSize": fileSize,
        "description": fileDescription ?? "",
        "isActive": isActive,
      },
      "tags": tags.isNotEmpty
          ? tags
          : [
              {"name": "default", "isActive": true}
            ],
    };

    try {
      final response =
          await _postRequest(endpoint, payload, customTimeout: extendedTimeout);

      if (response == null) {
        logSafe("Upload document failed: null response", level: LogLevel.error);
        return false;
      }

      logSafe("Upload document response status: ${response.statusCode}");
      logSafe("Upload document response body: ${response.body}");

      final json = jsonDecode(response.body);
      if (json['success'] == true) {
        logSafe("Document uploaded successfully: ${json['data']}");
        return true;
      } else {
        logSafe(
          "Failed to upload document: ${json['message'] ?? 'Unknown error'}",
          level: LogLevel.warning,
        );
      }
    } catch (e, stack) {
      logSafe("Exception during uploadDocumentApi: $e", level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return false;
  }

  /// Get Master Document Tags
  static Future<TagResponse?> getMasterDocumentTagsApi() async {
    const endpoint = ApiEndpoints.getMasterDocumentTags;
    logSafe("Fetching master document tags...");

    try {
      final response = await _getRequest(endpoint);

      if (response == null) {
        logSafe("Tags request failed: null response", level: LogLevel.error);
        return null;
      }

      final jsonResponse =
          _parseResponseForAllData(response, label: "Master Document Tags");

      if (jsonResponse != null) {
        return TagResponse.fromJson(jsonResponse);
      }
    } catch (e, stack) {
      logSafe("Exception during getMasterDocumentTagsApi: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return null;
  }

  /// Get Document List by EntityTypeId and EntityId
  static Future<DocumentsResponse?> getDocumentListApi({
    required String entityTypeId,
    required String entityId,
    String filter = "",
    String searchString = "",
    bool isActive = true,
    int pageNumber = 1,
    int pageSize = 20,
  }) async {
    final endpoint =
        "${ApiEndpoints.getDocumentList}/$entityTypeId/entity/$entityId";
    final queryParams = {
      "filter": filter,
      "searchString": searchString,
      "isActive": isActive.toString(),
      "pageNumber": pageNumber.toString(),
      "pageSize": pageSize.toString(),
    };

    logSafe(
        "Fetching document list for entityTypeId: $entityTypeId, entityId: $entityId");

    try {
      final response = await _getRequest(endpoint, queryParams: queryParams);

      if (response == null) {
        logSafe("Document list request failed: null response",
            level: LogLevel.error);
        return null;
      }

      final jsonResponse =
          _parseResponseForAllData(response, label: "Document List");

      if (jsonResponse != null) {
        return DocumentsResponse.fromJson(jsonResponse);
      }
    } catch (e, stack) {
      logSafe("Exception during getDocumentListApi: $e", level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return null;
  }

  /// Get Document Filters by EntityTypeId
  static Future<DocumentFiltersResponse?> getDocumentFilters(
      String entityTypeId) async {
    final endpoint = "${ApiEndpoints.getDocumentFilter}/$entityTypeId";
    logSafe("Fetching document filters for entityTypeId: $entityTypeId");

    try {
      final response = await _getRequest(endpoint, queryParams: null);

      if (response == null) {
        logSafe("Document filter request failed: null response",
            level: LogLevel.error);
        return null;
      }

      final jsonResponse =
          _parseResponseForAllData(response, label: "Document Filters");

      if (jsonResponse != null) {
        return DocumentFiltersResponse.fromJson(jsonResponse);
      }
    } catch (e, stack) {
      logSafe("Exception during getDocumentFilters: $e", level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return null;
  }

// === Menu APIs === //

  /// Get Sidebar Menu API
  static Future<Map<String, dynamic>?> getMenuApi() async {
    logSafe("Fetching sidebar menu...");

    try {
      final response = await _getRequest(ApiEndpoints.getDynamicMenu);
      if (response == null) {
        logSafe("Menu request failed: null response", level: LogLevel.error);
        return null;
      }

      final body = response.body.trim();
      if (body.isEmpty) {
        logSafe("Menu response body is empty", level: LogLevel.error);
        return null;
      }

      final jsonResponse = jsonDecode(body);
      if (jsonResponse is Map<String, dynamic>) {
        if (jsonResponse['success'] == true) {
          logSafe("Sidebar menu fetched successfully");
          return jsonResponse; // ✅ return full response
        } else {
          logSafe(
            "Failed to fetch sidebar menu: ${jsonResponse['message'] ?? 'Unknown error'}",
            level: LogLevel.warning,
          );
        }
      } else {
        logSafe("Unexpected response structure: $jsonResponse",
            level: LogLevel.error);
      }
    } catch (e, stack) {
      logSafe("Exception during getMenuApi: $e", level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return null;
  }

// === Expense APIs === //

  /// Edit Expense API
  static Future<bool> editExpenseApi({
    required String expenseId,
    required Map<String, dynamic> payload,
  }) async {
    final endpoint = "${ApiEndpoints.editExpense}/$expenseId";
    logSafe("Editing expense $expenseId with payload: $payload");

    try {
      final response = await _putRequest(
        endpoint,
        payload,
        customTimeout: extendedTimeout,
      );

      if (response == null) {
        logSafe("Edit expense failed: null response", level: LogLevel.error);
        return false;
      }

      logSafe("Edit expense response status: ${response.statusCode}");
      logSafe("Edit expense response body: ${response.body}");

      final json = jsonDecode(response.body);
      if (json['success'] == true) {
        logSafe("Expense updated successfully: ${json['data']}");
        return true;
      } else {
        logSafe(
          "Failed to update expense: ${json['message'] ?? 'Unknown error'}",
          level: LogLevel.warning,
        );
      }
    } catch (e, stack) {
      logSafe("Exception during editExpenseApi: $e", level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return false;
  }

  static Future<bool> deleteExpense(String expenseId) async {
    final endpoint = "${ApiEndpoints.deleteExpense}/$expenseId";

    try {
      final token = await _getToken();
      if (token == null) {
        logSafe("Token is null. Cannot proceed with DELETE request.",
            level: LogLevel.error);
        return false;
      }

      final uri = Uri.parse("${ApiEndpoints.baseUrl}$endpoint");

      logSafe("Sending DELETE request to $uri", level: LogLevel.debug);

      final response = await http
          .delete(uri, headers: _headers(token))
          .timeout(extendedTimeout);

      logSafe("DELETE expense response status: ${response.statusCode}");
      logSafe("DELETE expense response body: ${response.body}");

      final json = jsonDecode(response.body);
      if (response.statusCode == 200 && json['success'] == true) {
        logSafe("Expense deleted successfully.");
        return true;
      } else {
        logSafe(
            "Failed to delete expense: ${json['message'] ?? 'Unknown error'}",
            level: LogLevel.warning);
      }
    } catch (e, stack) {
      logSafe("Exception during deleteExpenseApi: $e", level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return false;
  }

  /// Get Expense Details API
  static Future<Map<String, dynamic>?> getExpenseDetailsApi({
    required String expenseId,
  }) async {
    final endpoint = "${ApiEndpoints.getExpenseDetails}/$expenseId";
    logSafe("Fetching expense details for ID: $expenseId");

    try {
      final response = await _getRequest(endpoint);
      if (response == null) {
        logSafe("Expense details request failed: null response",
            level: LogLevel.error);
        return null;
      }

      final body = response.body.trim();
      if (body.isEmpty) {
        logSafe("Expense details response body is empty",
            level: LogLevel.error);
        return null;
      }

      final jsonResponse = jsonDecode(body);
      if (jsonResponse is Map<String, dynamic>) {
        if (jsonResponse['success'] == true) {
          logSafe("Expense details fetched successfully");
          return jsonResponse['data']; // Return the expense details object
        } else {
          logSafe(
            "Failed to fetch expense details: ${jsonResponse['message'] ?? 'Unknown error'}",
            level: LogLevel.warning,
          );
        }
      } else {
        logSafe("Unexpected response structure: $jsonResponse",
            level: LogLevel.error);
      }
    } catch (e, stack) {
      logSafe("Exception during getExpenseDetailsApi: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return null;
  }

  /// Update Expense Status API
  static Future<bool> updateExpenseStatusApi({
    required String expenseId,
    required String statusId,
    String? comment,
    String? reimburseTransactionId,
    String? reimburseDate,
    String? reimbursedById,
    double? baseAmount,
    double? taxAmount,
    double? tdsPercent,
    double? netPayable,
  }) async {
    final Map<String, dynamic> payload = {
      "expenseId": expenseId,
      "statusId": statusId,
    };

    if (comment != null) payload["comment"] = comment;
    if (reimburseTransactionId != null)
      payload["reimburseTransactionId"] = reimburseTransactionId;
    if (reimburseDate != null) payload["reimburseDate"] = reimburseDate;
    if (reimbursedById != null) payload["reimburseById"] = reimbursedById;
    if (baseAmount != null) payload["baseAmount"] = baseAmount;
    if (taxAmount != null) payload["taxAmount"] = taxAmount;
    if (tdsPercent != null) payload["tdsPercent"] = tdsPercent;
    if (netPayable != null) payload["netPayable"] = netPayable;

    const endpoint = ApiEndpoints.updateExpenseStatus;
    logSafe("Updating expense status with payload: $payload");

    try {
      final response =
          await _postRequest(endpoint, payload, customTimeout: extendedTimeout);

      if (response == null) {
        logSafe("Update expense status failed: null response",
            level: LogLevel.error);
        return false;
      }

      logSafe("Update expense status response status: ${response.statusCode}");
      logSafe("Update expense status response body: ${response.body}");

      final json = jsonDecode(response.body);
      if (json['success'] == true) {
        logSafe("Expense status updated successfully: ${json['data']}");
        return true;
      } else {
        logSafe(
          "Failed to update expense status: ${json['message'] ?? 'Unknown error'}",
          level: LogLevel.warning,
        );
      }
    } catch (e, stack) {
      logSafe("Exception during updateExpenseStatus API: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return false;
  }

  static Future<Map<String, dynamic>?> getExpenseListApi({
    String? filter,
    int pageSize = 20,
    int pageNumber = 1,
  }) async {
    String endpoint = ApiEndpoints.getExpenseList;
    final queryParams = {
      'pageSize': pageSize.toString(),
      'pageNumber': pageNumber.toString(),
    };

    if (filter?.isNotEmpty ?? false) {
      queryParams['filter'] = filter!;
    }

    final uri = Uri.parse(endpoint).replace(queryParameters: queryParams);
    logSafe("Fetching expense list with URI: $uri");

    try {
      final response = await _getRequest(uri.toString());
      if (response == null) {
        logSafe("Expense list request failed: null response",
            level: LogLevel.error);
        return null; // real failure
      }

      final body = response.body.trim();
      if (body.isEmpty) {
        logSafe("Expense list response body is empty", level: LogLevel.warning);
        return {
          "status": true,
          "data": {"data": [], "totalPages": 0, "currentPage": pageNumber}
        }; // treat as empty list
      }

      final jsonResponse = jsonDecode(body);
      if (jsonResponse is Map<String, dynamic>) {
        logSafe("Expense list response parsed successfully");
        return jsonResponse; // always return valid JSON, even if data list is empty
      } else {
        logSafe("Unexpected response structure: $jsonResponse",
            level: LogLevel.error);
        return null;
      }
    } catch (e, stack) {
      logSafe("Exception during getExpenseListApi: $e", level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
      return null;
    }
  }

  static Future<List<AdvancePayment>> getAdvancePayments(
      String employeeId) async {
    try {
      final endpoint = "${ApiEndpoints.getAdvancePayments}/$employeeId";

      final response = await _getRequest(endpoint);

      if (response == null) {
        logSafe("❌ getAdvancePayments: Null response");
        return [];
      }

      if (response.statusCode == 200) {
        // 🟢 Added log to inspect raw JSON
        logSafe("🔍 AdvancePayment raw response: ${response.body}");

        final Map<String, dynamic> body = jsonDecode(response.body);
        final data = body['data'] ?? body;
        return AdvancePayment.listFromJson(data);
      } else {
        logSafe("⚠ getAdvancePayments failed → ${response.statusCode}");
        return [];
      }
    } catch (e, s) {
      logSafe("❌ ApiService.getAdvancePayments error: $e\n$s",
          level: LogLevel.error);
      return [];
    }
  }

  /// Fetch employees with optional query. Returns raw list (List<dynamic>)
  static Future<List<dynamic>> getEmployees(
      {Map<String, String>? queryParams}) async {
    try {
      final endpoint = ApiEndpoints.getEmployeesWithoutPermission;

      final resp = await _getRequest(endpoint, queryParams: queryParams);
      if (resp == null) return [];

      final body = jsonDecode(resp.body);
      if (body is Map && body.containsKey('data')) {
        final data = body['data'];
        if (data is List) return data;
        return [];
      } else if (body is List) {
        return body;
      } else {
        return [];
      }
    } catch (e, s) {
      logSafe("❌ ApiService.getEmployees error: $e\n$s", level: LogLevel.error);
      return [];
    }
  }

  /// Fetch Master Payment Modes
  static Future<List<dynamic>?> getMasterPaymentModes() async {
    const endpoint = ApiEndpoints.getMasterPaymentModes;
    return _getRequest(endpoint).then((res) => res != null
        ? _parseResponse(res, label: 'Master Payment Modes')
        : null);
  }

  /// Fetch Master Expense Status
  static Future<List<dynamic>?> getMasterExpenseStatus() async {
    const endpoint = ApiEndpoints.getMasterExpenseStatus;
    return _getRequest(endpoint).then((res) => res != null
        ? _parseResponse(res, label: 'Master Expense Status')
        : null);
  }

  /// Fetch Master Expense Categorys
  static Future<List<dynamic>?> getMasterExpenseTypes() async {
    const endpoint = ApiEndpoints.getMasterExpenseCategory;
    return _getRequest(endpoint).then((res) => res != null
        ? _parseResponse(res, label: 'Master Expense Categorys')
        : null);
  }

  /// Create Expense API
  static Future<bool> createExpenseApi({
    required String projectId,
    required String expensesTypeId,
    required String paymentModeId,
    required String paidById,
    required DateTime transactionDate,
    required String transactionId,
    required String description,
    required String location,
    required String supplerName,
    required double amount,
    required int noOfPersons,
    required List<Map<String, dynamic>> billAttachments,
  }) async {
    final payload = {
      "projectId": projectId,
      "expenseCategoryId": expensesTypeId,
      "paymentModeId": paymentModeId,
      "paidById": paidById,
      "transactionDate": transactionDate.toIso8601String(),
      "transactionId": transactionId,
      "description": description,
      "location": location,
      "supplerName": supplerName,
      "amount": amount,
      "noOfPersons": noOfPersons,
      "billAttachments": billAttachments,
    };

    const endpoint = ApiEndpoints.createExpense;
    logSafe("Creating expense with payload: $payload");

    try {
      final response =
          await _postRequest(endpoint, payload, customTimeout: extendedTimeout);

      if (response == null) {
        logSafe("Create expense failed: null response", level: LogLevel.error);
        return false;
      }

      logSafe("Create expense response status: ${response.statusCode}");
      logSafe("Create expense response body: ${response.body}");

      final json = jsonDecode(response.body);
      if (json['success'] == true) {
        logSafe("Expense created successfully: ${json['data']}");
        return true;
      } else {
        logSafe(
            "Failed to create expense: ${json['message'] ?? 'Unknown error'}",
            level: LogLevel.warning);
      }
    } catch (e, stack) {
      logSafe("Exception during createExpense API: $e", level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return false;
  }

  // === Dashboard Endpoints ===
  /// Get Dashboard Tasks
  static Future<DashboardTasks?> getDashboardTasks(
      {required String projectId}) async {
    try {
      final queryParams = {'projectId': projectId};

      final response = await _getRequest(ApiEndpoints.getDashboardTasks,
          queryParams: queryParams);

      if (response == null || response.body.trim().isEmpty) {
        logSafe("Dashboard tasks request failed or response empty",
            level: LogLevel.error);
        return null;
      }

      final jsonResponse = jsonDecode(response.body);
      if (jsonResponse is Map<String, dynamic> &&
          jsonResponse['success'] == true) {
        logSafe(
            "Dashboard tasks fetched successfully: ${jsonResponse['data']}");
        return DashboardTasks.fromJson(jsonResponse);
      } else {
        logSafe(
            "Failed to fetch dashboard tasks: ${jsonResponse['message'] ?? 'Unknown error'}",
            level: LogLevel.warning);
      }
    } catch (e, stack) {
      logSafe("Exception during getDashboardTasks API: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }
    return null;
  }

  /// Get Dashboard Teams
  static Future<DashboardTeams?> getDashboardTeams(
      {required String projectId}) async {
    try {
      final queryParams = {'projectId': projectId};

      final response = await _getRequest(ApiEndpoints.getDashboardTeams,
          queryParams: queryParams);

      if (response == null || response.body.trim().isEmpty) {
        logSafe("Dashboard teams request failed or response empty",
            level: LogLevel.error);
        return null;
      }

      final jsonResponse = jsonDecode(response.body);
      if (jsonResponse is Map<String, dynamic> &&
          jsonResponse['success'] == true) {
        logSafe(
            "Dashboard teams fetched successfully: ${jsonResponse['data']}");
        return DashboardTeams.fromJson(jsonResponse);
      } else {
        logSafe(
            "Failed to fetch dashboard teams: ${jsonResponse['message'] ?? 'Unknown error'}",
            level: LogLevel.warning);
      }
    } catch (e, stack) {
      logSafe("Exception during getDashboardTeams API: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }
    return null;
  }

  static Future<List<dynamic>?> getDashboardAttendanceOverview(
      String projectId, int days) async {
    if (projectId.isEmpty) throw ArgumentError('projectId must not be empty');
    if (days <= 0) throw ArgumentError('days must be greater than 0');

    final endpoint =
        "${ApiEndpoints.getDashboardAttendanceOverview}/$projectId?days=$days";

    return _getRequest(endpoint).then((res) => res != null
        ? _parseResponse(res, label: 'Dashboard Attendance Overview')
        : null);
  }

  /// Fetch Project Progress
  static Future<ProjectResponse?> getProjectProgress({
    required String projectId,
    required int days,
    DateTime? fromDate, // make optional
  }) async {
    const endpoint = ApiEndpoints.getDashboardProjectProgress;

    // Use today's date if fromDate is not provided
    final actualFromDate = fromDate ?? DateTime.now();

    final queryParams = {
      "projectId": projectId,
      "days": days.toString(),
      "FromDate":
          DateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS").format(actualFromDate),
    };

    try {
      final response = await _getRequest(endpoint, queryParams: queryParams);

      if (response == null) {
        logSafe(
          "Project Progress request failed: null response",
          level: LogLevel.error,
        );
        return null;
      }

      final parsed =
          _parseResponseForAllData(response, label: "ProjectProgress");
      if (parsed != null) {
        logSafe("✅ Project progress fetched successfully");
        return ProjectResponse.fromJson(parsed);
      }
    } catch (e, stack) {
      logSafe("Exception during getProjectProgress: $e", level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return null;
  }

  /// Directory calling the API

  static Future<bool> deleteBucket(String id) async {
    final endpoint = "${ApiEndpoints.updateBucket}/$id";

    try {
      final token = await _getToken();
      if (token == null) {
        logSafe("Token is null. Cannot proceed with DELETE request.",
            level: LogLevel.error);
        return false;
      }

      final uri = Uri.parse("${ApiEndpoints.baseUrl}$endpoint");

      logSafe("Sending DELETE request to $uri", level: LogLevel.debug);

      final response = await http
          .delete(uri, headers: _headers(token))
          .timeout(extendedTimeout);

      logSafe("DELETE bucket response status: ${response.statusCode}");
      logSafe("DELETE bucket response body: ${response.body}");

      final json = jsonDecode(response.body);
      if (response.statusCode == 200 && json['success'] == true) {
        logSafe("Bucket deleted successfully.");
        return true;
      } else {
        logSafe(
            "Failed to delete bucket: ${json['message'] ?? 'Unknown error'}",
            level: LogLevel.warning);
      }
    } catch (e, stack) {
      logSafe("Exception during deleteBucket API: $e", level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return false;
  }

  static Future<bool> updateBucket({
    required String id,
    required String name,
    required String description,
  }) async {
    final payload = {
      "id": id,
      "name": name,
      "description": description,
    };

    final endpoint = "${ApiEndpoints.updateBucket}/$id";

    logSafe("Updating bucket with payload: $payload");

    try {
      final response = await _putRequest(endpoint, payload);

      if (response == null) {
        logSafe("Update bucket failed: null response", level: LogLevel.error);
        return false;
      }

      logSafe("Update bucket response status: ${response.statusCode}");
      logSafe("Update bucket response body: ${response.body}");

      final json = jsonDecode(response.body);
      if (json['success'] == true) {
        logSafe("Bucket updated successfully: ${json['data']}");
        return true;
      } else {
        logSafe("Failed to update bucket: ${json['message']}",
            level: LogLevel.warning);
      }
    } catch (e, stack) {
      logSafe("Exception during updateBucket API: $e", level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return false;
  }

  /// Assign employees to a bucket
  static Future<bool> assignEmployeesToBucket({
    required String bucketId,
    required List<Map<String, dynamic>> employees,
  }) async {
    final endpoint = "${ApiEndpoints.assignBucket}/$bucketId";

    logSafe("Assigning employees to bucket $bucketId: $employees");

    try {
      final response = await _postRequest(endpoint, employees);

      if (response == null) {
        logSafe("Assign employees failed: null response",
            level: LogLevel.error);
        return false;
      }

      logSafe("Assign employees response status: ${response.statusCode}");
      logSafe("Assign employees response body: ${response.body}");

      final json = jsonDecode(response.body);
      if (json['success'] == true) {
        logSafe("Employees assigned successfully");
        return true;
      } else {
        logSafe("Failed to assign employees: ${json['message']}",
            level: LogLevel.warning);
      }
    } catch (e, stack) {
      logSafe("Exception during assignEmployeesToBucket API: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return false;
  }

  static Future<bool> createBucket({
    required String name,
    required String description,
  }) async {
    final payload = {
      "name": name,
      "description": description,
    };

    final endpoint = ApiEndpoints.createBucket;

    logSafe("Creating bucket with payload: $payload");

    try {
      final response = await _postRequest(endpoint, payload);

      if (response == null) {
        logSafe("Create bucket failed: null response", level: LogLevel.error);
        return false;
      }

      logSafe("Create bucket response status: ${response.statusCode}");
      logSafe("Create bucket response body: ${response.body}");

      final json = jsonDecode(response.body);

      if (json['success'] == true) {
        logSafe("Bucket created successfully: ${json['data']}");
        return true;
      } else {
        logSafe("Failed to create bucket: ${json['message']}",
            level: LogLevel.warning);
      }
    } catch (e, stack) {
      logSafe("Exception during createBucket API: ${e.toString()}",
          level: LogLevel.error);
      logSafe("StackTrace: ${stack.toString()}", level: LogLevel.debug);
    }

    return false;
  }

  static Future<Map<String, dynamic>?> getDirectoryNotes({
    int pageSize = 1000,
    int pageNumber = 1,
  }) async {
    final queryParams = {
      'pageSize': pageSize.toString(),
      'pageNumber': pageNumber.toString(),
    };

    final response = await _getRequest(
      ApiEndpoints.getDirectoryNotes,
      queryParams: queryParams,
    );

    final data = response != null
        ? _parseResponse(response, label: 'Directory Notes')
        : null;

    return data is Map<String, dynamic> ? data : null;
  }

  static Future<bool> addContactComment(String note, String contactId) async {
    final payload = {
      "note": note,
      "contactId": contactId,
    };

    final endpoint = ApiEndpoints.updateDirectoryNotes;

    logSafe("Adding new comment with payload: $payload");
    logSafe("Sending add comment request to $endpoint");

    try {
      final response = await _postRequest(endpoint, payload);

      if (response == null) {
        logSafe("Add comment failed: null response", level: LogLevel.error);
        return false;
      }

      logSafe("Add comment response status: ${response.statusCode}");
      logSafe("Add comment response body: ${response.body}");

      final json = jsonDecode(response.body);

      if (json['success'] == true) {
        logSafe("Comment added successfully for contactId: $contactId");
        return true;
      } else {
        logSafe("Failed to add comment: ${json['message']}",
            level: LogLevel.warning);
      }
    } catch (e, stack) {
      logSafe("Exception during addComment API: ${e.toString()}",
          level: LogLevel.error);
      logSafe("StackTrace: ${stack.toString()}", level: LogLevel.debug);
    }

    return false;
  }

  /// Get list of assigned projects for a specific employee
  /// Get list of assigned projects for a specific employee
  static Future<List<dynamic>?> getAssignedProjects(String employeeId) async {
    if (employeeId.isEmpty) {
      throw ArgumentError("employeeId must not be empty");
    }

    final endpoint = "${ApiEndpoints.getAssignedProjects}/$employeeId";

    try {
      final response = await _getRequest(endpoint);

      if (response == null) {
        logSafe("Failed to fetch assigned projects: null response",
            level: LogLevel.error);
        return null;
      }

      final parsed = _parseResponse(response, label: "Assigned Projects");
      if (parsed is List) {
        return parsed;
      } else {
        logSafe("Unexpected response format for assigned projects.",
            level: LogLevel.error);
        return null;
      }
    } catch (e, stack) {
      logSafe("Exception during getAssignedProjects API: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
      return null;
    }
  }

  /// Assign projects to a specific employee
  static Future<bool> assignProjects({
    required String employeeId,
    required List<Map<String, dynamic>> projects,
  }) async {
    if (employeeId.isEmpty) {
      throw ArgumentError("employeeId must not be empty");
    }
    if (projects.isEmpty) {
      throw ArgumentError("projects list must not be empty");
    }

    final endpoint = "${ApiEndpoints.assignProjects}/$employeeId";

    logSafe("Assigning projects to employee $employeeId: $projects");

    try {
      final response = await _postRequest(endpoint, projects);

      if (response == null) {
        logSafe("Assign projects failed: null response", level: LogLevel.error);
        return false;
      }

      logSafe("Assign projects response status: ${response.statusCode}");
      logSafe("Assign projects response body: ${response.body}");

      final json = jsonDecode(response.body);
      if (json['success'] == true) {
        logSafe("Projects assigned successfully");
        return true;
      } else {
        logSafe("Failed to assign projects: ${json['message']}",
            level: LogLevel.warning);
      }
    } catch (e, stack) {
      logSafe("Exception during assignProjects API: $e", level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return false;
  }

  static Future<bool> updateContactComment(
      String commentId, String note, String contactId) async {
    final payload = {
      "id": commentId,
      "contactId": contactId,
      "note": note,
    };

    final endpoint = "${ApiEndpoints.updateDirectoryNotes}/$commentId";

    final headers = {
      "comment-id": commentId,
    };

    logSafe("Updating comment with payload: $payload");
    logSafe("Headers for update comment: $headers");
    logSafe("Sending update comment request to $endpoint");

    try {
      final response = await _putRequest(
        endpoint,
        payload,
        additionalHeaders: headers,
      );

      if (response == null) {
        logSafe("Update comment failed: null response", level: LogLevel.error);
        return false;
      }

      logSafe("Update comment response status: ${response.statusCode}");
      logSafe("Update comment response body: ${response.body}");

      final json = jsonDecode(response.body);

      if (json['success'] == true) {
        logSafe("Comment updated successfully. commentId: $commentId");
        return true;
      } else {
        logSafe("Failed to update comment: ${json['message']}",
            level: LogLevel.warning);
      }
    } catch (e, stack) {
      logSafe("Exception during updateComment API: ${e.toString()}",
          level: LogLevel.error);
      logSafe("StackTrace: ${stack.toString()}", level: LogLevel.debug);
    }

    return false;
  }

  static Future<bool> restoreContactComment(
    String commentId,
    bool isActive,
  ) async {
    final endpoint =
        "${ApiEndpoints.updateDirectoryNotes}/$commentId?active=$isActive";

    logSafe(
        "Updating comment active status. commentId: $commentId, isActive: $isActive");
    logSafe("Sending request to $endpoint ");

    try {
      final response = await _deleteRequest(
        endpoint,
      );

      if (response == null) {
        logSafe("Update comment failed: null response", level: LogLevel.error);
        return false;
      }

      logSafe("Update comment response status: ${response.statusCode}");
      logSafe("Update comment response body: ${response.body}");

      final json = jsonDecode(response.body);
      if (json['success'] == true) {
        logSafe(
            "Comment active status updated successfully. commentId: $commentId");
        return true;
      } else {
        logSafe("Failed to update comment: ${json['message']}",
            level: LogLevel.warning);
      }
    } catch (e, stack) {
      logSafe("Exception during updateComment API: ${e.toString()}",
          level: LogLevel.error);
      logSafe("StackTrace: ${stack.toString()}", level: LogLevel.debug);
    }

    return false;
  }

  static Future<List<dynamic>?> getDirectoryComments(
    String contactId, {
    bool active = true,
  }) async {
    final url = "${ApiEndpoints.getDirectoryNotes}/$contactId?active=$active";
    final response = await _getRequest(url);
    final data = response != null
        ? _parseResponse(response, label: 'Directory Comments')
        : null;

    return data is List ? data : null;
  }

  /// Deletes a directory contact (sets active=false)
  static Future<bool> deleteDirectoryContact(String contactId) async {
    final endpoint = "${ApiEndpoints.updateContact}/$contactId/";
    final queryParams = {'active': 'false'};

    final uri = Uri.parse("${ApiEndpoints.baseUrl}$endpoint")
        .replace(queryParameters: queryParams);

    _log("Deleting directory contact at $uri");

    final response = await _deleteRequest(
      "$endpoint?active=false",
    );

    if (response != null && response.statusCode == 200) {
      _log("Contact deleted successfully: ${response.body}");
      return true;
    }

    _log("Failed to delete contact: ${response?.body}");
    return false;
  }

  /// Restores a directory contact (sets active=true)
  static Future<bool> restoreDirectoryContact(String contactId) async {
    final endpoint = "${ApiEndpoints.updateContact}/$contactId/";
    final queryParams = {'active': 'true'};

    final uri = Uri.parse("${ApiEndpoints.baseUrl}$endpoint")
        .replace(queryParameters: queryParams);

    _log("Restoring directory contact at $uri");

    final response = await _deleteRequest(
      "$endpoint?active=true",
    );

    if (response != null && response.statusCode == 200) {
      _log("Contact restored successfully: ${response.body}");
      return true;
    }

    _log("Failed to restore contact: ${response?.body}");
    return false;
  }

  static Future<bool> updateContact(
      String contactId, Map<String, dynamic> payload) async {
    try {
      final endpoint = "${ApiEndpoints.updateContact}/$contactId";

      logSafe("Updating contact [$contactId] with payload: $payload");

      final response = await _putRequest(endpoint, payload);
      if (response != null) {
        final json = jsonDecode(response.body);
        if (json['success'] == true) {
          logSafe("Contact updated successfully.");
          return true;
        } else {
          logSafe("Update contact failed: ${json['message']}",
              level: LogLevel.warning);
        }
      }
    } catch (e) {
      logSafe("Error updating contact: $e", level: LogLevel.error);
    }
    return false;
  }

  static Future<bool> createContact(Map<String, dynamic> payload) async {
    try {
      logSafe("Submitting contact payload: $payload");

      final response = await _postRequest(ApiEndpoints.createContact, payload);
      if (response != null) {
        final json = jsonDecode(response.body);
        if (json['success'] == true) {
          logSafe("Contact created successfully.");
          return true;
        } else {
          logSafe("Create contact failed: ${json['message']}",
              level: LogLevel.warning);
        }
      }
    } catch (e) {
      logSafe("Error creating contact: $e", level: LogLevel.error);
    }
    return false;
  }

  static Future<List<String>> getOrganizationList() async {
    try {
      final url = ApiEndpoints.getDirectoryOrganization;
      logSafe("Sending GET request to: $url", level: LogLevel.info);

      final response = await _getRequest(url);

      logSafe("Response status: ${response?.statusCode}",
          level: LogLevel.debug);
      logSafe("Response body: ${response?.body}", level: LogLevel.debug);

      if (response != null && response.statusCode == 200) {
        final body = jsonDecode(response.body);
        if (body['success'] == true && body['data'] is List) {
          return List<String>.from(body['data']);
        }
      }
    } catch (e, stackTrace) {
      logSafe("Failed to fetch organization names: $e", level: LogLevel.error);
      logSafe("Stack trace: $stackTrace", level: LogLevel.debug);
    }
    return [];
  }

  static Future<Map<String, dynamic>?> getContactCategoryList() async =>
      _getRequest(ApiEndpoints.getDirectoryContactCategory).then((res) =>
          res != null
              ? _parseResponseForAllData(res, label: 'Contact Category List')
              : null);

  static Future<Map<String, dynamic>?> getContactTagList() async =>
      _getRequest(ApiEndpoints.getDirectoryContactTags).then((res) =>
          res != null
              ? _parseResponseForAllData(res, label: 'Contact Tag List')
              : null);

  static Future<List<dynamic>?> getDirectoryData(
      {required bool isActive}) async {
    final queryParams = {
      "active": isActive.toString(),
    };

    return _getRequest(ApiEndpoints.getDirectoryContacts,
            queryParams: queryParams)
        .then((res) =>
            res != null ? _parseResponse(res, label: 'Directory Data') : null);
  }

  static Future<Map<String, dynamic>?> getContactBucketList() async =>
      _getRequest(ApiEndpoints.getDirectoryBucketList).then((res) => res != null
          ? _parseResponseForAllData(res, label: 'Contact Bucket List')
          : null);

  // === Attendance APIs ===

  static Future<List<dynamic>?> getProjects() async =>
      _getRequest(ApiEndpoints.getProjects).then(
          (res) => res != null ? _parseResponse(res, label: 'Projects') : null);

  static Future<List<dynamic>?> getGlobalProjects() async =>
      _getRequest(ApiEndpoints.getGlobalProjects).then((res) =>
          res != null ? _parseResponse(res, label: 'Global Projects') : null);

  static Future<List<dynamic>?> getTodaysAttendance(
    String projectId, {
    String? organizationId,
  }) async {
    final query = {
      "projectId": projectId,
      if (organizationId != null) "organizationId": organizationId,
    };

    return _getRequest(ApiEndpoints.getTodaysAttendance, queryParams: query)
        .then((res) =>
            res != null ? _parseResponse(res, label: 'Employees') : null);
  }

  static Future<List<EmployeeModel>?> getAttendanceForDashboard(
      String projectId) async {
    String endpoint = ApiEndpoints.getAttendanceForDashboard.replaceFirst(
      ':projectId',
      projectId,
    );

    final res = await _getRequest(endpoint);

    if (res == null) return null;

    final data = _parseResponse(res, label: 'Dashboard Attendance');
    if (data == null) return null;

    // Wrap single object in a list if needed
    if (data is Map<String, dynamic>) {
      return [EmployeeModel.fromJson(data)];
    } else if (data is List) {
      return data.map((e) => EmployeeModel.fromJson(e)).toList();
    }

    return null;
  }

  static Future<List<dynamic>?> getRegularizationLogs(
    String projectId, {
    String? organizationId,
  }) async {
    final query = {
      "projectId": projectId,
      if (organizationId != null) "organizationId": organizationId,
    };

    return _getRequest(ApiEndpoints.getRegularizationLogs, queryParams: query)
        .then((res) => res != null
            ? _parseResponse(res, label: 'Regularization Logs')
            : null);
  }

  static Future<List<dynamic>?> getAttendanceLogs(
    String projectId, {
    DateTime? dateFrom,
    DateTime? dateTo,
    String? organizationId,
  }) async {
    final query = {
      "projectId": projectId,
      if (dateFrom != null)
        "dateFrom": DateFormat('yyyy-MM-dd').format(dateFrom),
      if (dateTo != null) "dateTo": DateFormat('yyyy-MM-dd').format(dateTo),
      if (organizationId != null) "organizationId": organizationId,
    };

    return _getRequest(ApiEndpoints.getAttendanceLogs, queryParams: query).then(
        (res) =>
            res != null ? _parseResponse(res, label: 'Attendance Logs') : null);
  }

  static Future<List<dynamic>?> getAttendanceLogView(String id) async =>
      _getRequest("${ApiEndpoints.getAttendanceLogView}/$id").then((res) =>
          res != null ? _parseResponse(res, label: 'Log Details') : null);

  static Future<bool> uploadAttendanceImage(
    String id,
    String employeeId,
    XFile? imageFile,
    double latitude,
    double longitude, {
    required String imageName,
    required String projectId,
    String comment = "",
    required int action,
    bool imageCapture = true,
    required String markTime, // 👈 now required
    required String date, // 👈 new required param
  }) async {
    final body = {
      "id": id,
      "employeeId": employeeId,
      "projectId": projectId,
      "markTime": markTime, // 👈 directly from UI
      "comment": comment,
      "action": action,
      "date": date, // 👈 directly from UI
      if (imageCapture) "latitude": '$latitude',
      if (imageCapture) "longitude": '$longitude',
    };

    if (imageCapture && imageFile != null) {
      try {
        final bytes = await imageFile.readAsBytes();
        final fileSize = await imageFile.length();
        final contentType = "image/${imageFile.path.split('.').last}";
        body["image"] = {
          "fileName": imageName,
          "contentType": contentType,
          "fileSize": fileSize,
          "description": "Employee attendance photo",
          "base64Data": base64Encode(bytes),
        };
      } catch (e) {
        logSafe("Image encoding error: $e", level: LogLevel.error);
        return false;
      }
    }

    final response = await _postRequest(
      ApiEndpoints.uploadAttendanceImage,
      body,
      customTimeout: extendedTimeout,
    );

    if (response == null) return false;

    final json = jsonDecode(response.body);
    if (response.statusCode == 200 && json['success'] == true) return true;

    logSafe("Failed to upload image: ${json['message'] ?? 'Unknown error'}");
    return false;
  }

  static String generateImageName(String employeeId, int count) {
    final now = DateTime.now();
    final dateStr = DateFormat('yyyyMMdd_HHmmss').format(now);
    final imageNumber = count.toString().padLeft(3, '0');
    return "${employeeId}_${dateStr}_$imageNumber.jpg";
  }

  // === Employee APIs ===
  /// Search employees by first name and last name only (not middle name)
  /// Returns a list of up to 10 employee records matching the search string.
  static Future<List<dynamic>?> searchEmployeesBasic({
    String? searchString,
  }) async {
    // Remove ArgumentError check because searchString is optional now

    final queryParams = <String, String>{};

    // Add searchString to query parameters only if it's not null or empty
    if (searchString != null && searchString.isNotEmpty) {
      queryParams['searchString'] = searchString;
    }

    final response = await _getRequest(
      ApiEndpoints.getEmployeesWithoutPermission,
      queryParams: queryParams,
    );

    if (response != null) {
      return _parseResponse(response, label: 'Search Employees Basic');
    }

    return null;
  }

  static Future<List<dynamic>?> getAllEmployeesByProject(String projectId,
      {String? organizationId}) async {
    if (projectId.isEmpty) throw ArgumentError('projectId must not be empty');

    // Build the endpoint with optional organizationId query
    var endpoint = "${ApiEndpoints.getAllEmployeesByProject}/$projectId";
    if (organizationId != null && organizationId.isNotEmpty) {
      endpoint += "?organizationId=$organizationId";
    }

    return _getRequest(endpoint).then(
      (res) => res != null
          ? _parseResponse(res, label: 'Employees by Project')
          : null,
    );
  }

  /// Fetches employees by projectId, serviceId, and organizationId
  static Future<List<dynamic>?> getEmployeesByProjectService(
    String projectId, {
    String? serviceId,
    String? organizationId,
  }) async {
    if (projectId.isEmpty) {
      throw ArgumentError('projectId must not be empty');
    }

    // Construct query parameters only if non-empty
    final queryParams = <String, String>{};
    if (serviceId != null && serviceId.isNotEmpty) {
      queryParams['serviceId'] = serviceId;
    }
    if (organizationId != null && organizationId.isNotEmpty) {
      queryParams['organizationId'] = organizationId;
    }

    final endpoint = "${ApiEndpoints.getAllEmployeesByOrganization}/$projectId";

    final response = await _getRequest(endpoint, queryParams: queryParams);

    if (response != null) {
      return _parseResponse(response, label: 'Employees by Project Service');
    } else {
      return null;
    }
  }

  static Future<List<dynamic>?> getAllEmployees(
      {String? organizationId}) async {
    var endpoint = ApiEndpoints.getAllEmployees;

    // Add organization filter if provided
    if (organizationId != null && organizationId.isNotEmpty) {
      endpoint += "?organizationId=$organizationId";
    }

    return _getRequest(endpoint).then(
      (res) => res != null ? _parseResponse(res, label: 'All Employees') : null,
    );
  }

  static Future<List<dynamic>?> getRoles() async =>
      _getRequest(ApiEndpoints.getRoles).then(
          (res) => res != null ? _parseResponse(res, label: 'Roles') : null);
  static Future<Map<String, dynamic>?> createEmployee({
    String? id,
    required String firstName,
    required String lastName,
    required String phoneNumber,
    required String gender,
    required String jobRoleId,
    required String joiningDate,
    String? email,
    String? organizationId,
    bool? hasApplicationAccess,
  }) async {
    final body = {
      if (id != null) "id": id,
      "firstName": firstName,
      "lastName": lastName,
      "phoneNumber": phoneNumber,
      "gender": gender,
      "jobRoleId": jobRoleId,
      "joiningDate": joiningDate,
      if (email != null && email.isNotEmpty) "email": email,
      if (organizationId != null && organizationId.isNotEmpty)
        "organizationId": organizationId,
      if (hasApplicationAccess != null)
        "hasApplicationAccess": hasApplicationAccess,
    };

    final response = await _postRequest(
      ApiEndpoints.createEmployee,
      body,
      customTimeout: extendedTimeout,
    );

    if (response == null) return null;

    final json = jsonDecode(response.body);
    return {
      "success": response.statusCode == 200 && json['success'] == true,
      "data": json,
    };
  }

  static Future<Map<String, dynamic>?> getEmployeeDetails(
      String employeeId) async {
    final url = "${ApiEndpoints.getEmployeeInfo}/$employeeId";
    final response = await _getRequest(url);
    final data = response != null
        ? _parseResponse(response, label: 'Employee Details')
        : null;
    return data is Map<String, dynamic> ? data : null;
  }

  // === Daily Task APIs ===
  /// Get Daily Task Project Report Filter
  static Future<DailyProgressReportFilterResponse?> getDailyTaskFilter(
      String projectId) async {
    final endpoint =
        "${ApiEndpoints.getDailyTaskProjectProgressFilter}/$projectId";
    logSafe("Fetching daily task Progress filter for projectId: $projectId");

    try {
      final response = await _getRequest(endpoint);

      if (response == null) {
        logSafe("Daily task filter request failed: null response",
            level: LogLevel.error);
        return null;
      }

      final jsonResponse = _parseResponseForAllData(response,
          label: "Daily Task Progress Filter");

      if (jsonResponse != null) {
        return DailyProgressReportFilterResponse.fromJson(jsonResponse);
      }
    } catch (e, stack) {
      logSafe("Exception during getDailyTask Progress Filter: $e",
          level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    }

    return null;
  }

  static Future<List<TaskModel>?> getDailyTasks(
    String projectId, {
    Map<String, dynamic>? filter,
    int pageNumber = 1,
    int pageSize = 20,
  }) async {
    // Build query parameters
    final query = {
      "projectId": projectId,
      "pageNumber": pageNumber.toString(),
      "pageSize": pageSize.toString(),
      if (filter != null) "filter": jsonEncode(filter),
    };

    final uri =
        Uri.parse(ApiEndpoints.getDailyTask).replace(queryParameters: query);

    final response = await _getRequest(uri.toString());
    final parsed = response != null
        ? _parseResponse(response, label: 'Daily Tasks')
        : null;

    if (parsed != null && parsed['data'] != null) {
      return (parsed['data'] as List)
          .map((e) => TaskModel.fromJson(e))
          .toList();
    }

    return null;
  }

  static Future<bool> reportTask({
    required String id,
    required int completedTask,
    required String comment,
    required List<Map<String, dynamic>> checkList,
    List<Map<String, dynamic>>? images,
  }) async {
    final body = {
      "id": id,
      "completedTask": completedTask,
      "comment": comment,
      "reportedDate": DateTime.now().toUtc().toIso8601String(),
      "checkList": checkList,
      if (images != null && images.isNotEmpty) "images": images,
    };

    final response = await _postRequest(
      ApiEndpoints.reportTask,
      body,
      customTimeout: extendedTimeout,
    );

    if (response == null) return false;
    final json = jsonDecode(response.body);
    if (response.statusCode == 200 && json['success'] == true) {
      Get.back();
      return true;
    }
    logSafe("Failed to report task: ${json['message'] ?? 'Unknown error'}");
    return false;
  }

  static Future<bool> commentTask({
    required String id,
    required String comment,
    List<Map<String, dynamic>>? images,
  }) async {
    final body = {
      "taskAllocationId": id,
      "comment": comment,
      "commentDate": DateTime.now().toUtc().toIso8601String(),
      if (images != null && images.isNotEmpty) "images": images,
    };

    final response = await _postRequest(ApiEndpoints.commentTask, body);
    if (response == null) return false;
    final json = jsonDecode(response.body);
    return response.statusCode == 200 && json['success'] == true;
  }

  /// Fetch infra details for a project, optionally filtered by service
  static Future<Map<String, dynamic>?> getInfraDetails(String projectId,
      {String? serviceId}) async {
    String endpoint = "/project/infra-details/$projectId";

    if (serviceId != null && serviceId.isNotEmpty) {
      endpoint += "?serviceId=$serviceId";
    }

    final res = await _getRequest(endpoint);
    if (res == null) {
      logSafe('Infra Details API returned null');
      return null;
    }

    logSafe('Infra Details raw response: ${res.body}');
    return _parseResponseForAllData(res, label: 'Infra Details')
        as Map<String, dynamic>?;
  }

  /// Fetch work items for a given work area, optionally filtered by service
  static Future<Map<String, dynamic>?> getWorkItemsByWorkArea(String workAreaId,
      {String? serviceId}) async {
    String endpoint = "/project/tasks/$workAreaId";

    if (serviceId != null && serviceId.isNotEmpty) {
      endpoint += "?serviceId=$serviceId";
    }

    final res = await _getRequest(endpoint);
    if (res == null) {
      logSafe('Work Items API returned null');
      return null;
    }

    logSafe('Work Items raw response: ${res.body}');
    return _parseResponseForAllData(res, label: 'Work Items')
        as Map<String, dynamic>?;
  }

  static Future<bool> assignDailyTask({
    required String workItemId,
    required int plannedTask,
    required String description,
    required List<String> taskTeam,
    DateTime? assignmentDate,
    String? organizationId,
    String? serviceId,
  }) async {
    final body = {
      "workItemId": workItemId,
      "plannedTask": plannedTask,
      "description": description,
      "taskTeam": taskTeam,
      "organizationId": organizationId,
      "serviceId": serviceId,
      "assignmentDate":
          (assignmentDate ?? DateTime.now()).toUtc().toIso8601String(),
    };
    final response = await _postRequest(ApiEndpoints.assignDailyTask, body);
    if (response == null) return false;
    final json = jsonDecode(response.body);
    if (response.statusCode == 200 && json['success'] == true) {
      Get.back();
      return true;
    }
    logSafe(
        "Failed to assign daily task: ${json['message'] ?? 'Unknown error'}");
    return false;
  }

  static Future<Map<String, dynamic>?> getWorkStatus() async {
    final res = await _getRequest(ApiEndpoints.getWorkStatus);
    if (res == null) {
      logSafe('Work Status API returned null');
      return null;
    }

    logSafe('Work Status raw response: ${res.body}');
    return _parseResponseForAllData(res, label: 'Work Status')
        as Map<String, dynamic>?;
  }

  static Future<Map<String, dynamic>?> getMasterWorkCategories() async =>
      _getRequest(ApiEndpoints.getmasterWorkCategories).then((res) =>
          res != null
              ? _parseResponseForAllData(res, label: 'Master Work Categories')
              : null);

  static Future<bool> approveTask({
    required String id,
    required String comment,
    required String workStatus,
    required int approvedTask,
    List<Map<String, dynamic>>? images,
  }) async {
    final body = {
      "id": id,
      "workStatus": workStatus,
      "approvedTask": approvedTask,
      "comment": comment,
      if (images != null && images.isNotEmpty) "images": images,
    };

    final response = await _postRequest(ApiEndpoints.approveReportAction, body);
    if (response == null) return false;

    final json = jsonDecode(response.body);
    return response.statusCode == 200 && json['success'] == true;
  }

  static Future<bool> createTask({
    required String parentTaskId,
    required int plannedTask,
    required String comment,
    required String workAreaId,
    required String activityId,
    DateTime? assignmentDate,
    required String categoryId,
  }) async {
    final body = [
      {
        "parentTaskId": parentTaskId,
        "plannedWork": plannedTask,
        "comment": comment,
        "workAreaID": workAreaId,
        "activityID": activityId,
        "workCategoryId": categoryId,
        'completedWork': 0,
      }
    ];

    final response = await _postRequest(ApiEndpoints.assignTask, body);
    if (response == null) return false;

    final json = jsonDecode(response.body);
    if (response.statusCode == 200 && json['success'] == true) {
      Get.back();
      return true;
    }

    logSafe("Failed to create task: ${json['message'] ?? 'Unknown error'}");
    return false;
  }
}
