import 'package:flutter/material.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart';
import 'package:test_sa/modules/site_request_module/models/dropdown_models.dart';
import 'package:test_sa/modules/site_request_module/models/request_type_model.dart';
import 'package:test_sa/modules/site_request_module/models/site_request_model.dart';
import 'package:test_sa/models/lookup.dart';
import 'dart:convert';
import 'package:http/http.dart';

/// Provider for managing site request operations including:
/// - Fetching request types
/// - Managing user's current sites
/// - Submitting site requests
/// - Fetching and paginating request history
class SiteRequestProvider extends ChangeNotifier {
  // Constants
  static const int _defaultPageSize = 10;
  static const String _errorFetchFailed = 'Failed to fetch data';
  static const String _errorSubmitFailed = 'Failed to submit request';

  // Loading states
  bool _loading = false;
  bool _isLoadingMore = false;

  // Data
  List<RequestTypeModel> _requestTypes = [];
  List<SiteRequestSiteModel> _userCurrentSites = [];
  List<SiteRequestModel> _requestHistory = [];

  // Pagination
  int _currentPage = 1;
  int _pageSize = _defaultPageSize;
  bool _hasMoreData = true;

  // Error handling
  String? _errorMessage;
  int? stateCode;

  // Getters
  bool get loading => _loading;

  bool get isLoadingMore => _isLoadingMore;

  String? get errorMessage => _errorMessage;

  int get currentPage => _currentPage;

  bool get hasMoreData => _hasMoreData;

  List<RequestTypeModel> get requestTypes => _requestTypes;

  List<SiteRequestSiteModel> get userCurrentSites => _userCurrentSites;

  List<SiteRequestModel> get requestHistory => _requestHistory;

  // User helper methods
  String getCurrentUserUserId(UserProvider userProvider) => userProvider.user?.userID ?? '';

  String getCurrentUserEmployeeId(UserProvider userProvider) => userProvider.user?.employeeId ?? '';

  String getCurrentUserFullName(UserProvider userProvider) => userProvider.user?.username ?? '';

  String getCurrentUserEmail(UserProvider userProvider) => userProvider.user?.email ?? '';

  String getCurrentUserMobile(UserProvider userProvider) => userProvider.user?.mobileNumber ?? '';

  String getCurrentUserExtension(UserProvider userProvider) => userProvider.user?.extensionNo ?? '';

  String getCurrentUserRole(UserProvider userProvider) {
    if (userProvider.user?.userRoles != null && userProvider.user!.userRoles!.isNotEmpty) {
      return userProvider.user!.userRoles!.first.name ?? '';
    }
    return '';
  }

  List<String> getCurrentUserAssignedSites(UserProvider userProvider) => [];

  bool hasAssignedSites(List<String> assignedSites) => assignedSites.isNotEmpty;

  // Setter
  set loading(bool value) {
    _loading = value;
    notifyListeners();
  }

  /// Fetches available request types from the server
  Future<int> fetchRequestTypes() async {
    if (_loading) return -2;

    return _performApiCall(
      apiCall: () => ApiManager.instance.get(URLs.getSiteRequestTypes, enableToastMessage: false),
      onSuccess: (responseData) {
        List listJson = responseData['data'] ?? responseData;
        _requestTypes = listJson
            .map((item) => Lookup.fromJson(item))
            .map((lookup) => RequestTypeModel(
                  id: lookup.id?.toString() ?? lookup.value?.toString() ?? '',
                  name: lookup.name ?? '',
                  value: lookup.value,
                ))
            .toList();
      },
      errorMessage: 'Failed to fetch request types',
    );
  }

  /// Fetches user's current sites for Change/Remove Site operations
  Future<int> fetchUserCurrentSites(String userId) async {
    if (_loading) return -2;

    return _performApiCall(
      apiCall: () => ApiManager.instance.post(URLs.getUserSites(userId), showToast: false, body: {}),
      onSuccess: (responseData) {
        List listJson = responseData['data'] ?? [];
        _userCurrentSites = listJson
            .map((item) => SiteRequestSiteModel(
                  id: item['siteId']?.toString() ?? '',
                  name: item['siteName'] ?? '',
                ))
            .toList();
      },
      errorMessage: 'Failed to fetch user sites',
    );
  }

  /// Submits a site request to the server
  Future<bool> submitSiteRequest(SiteRequestModel request, UserProvider userProvider) async {
    loading = true;
    _errorMessage = null;
    notifyListeners();

    try {
      final isChangeSiteRequest = _requestTypes.any((type) => type.identifier == request.requestType && (type.name?.toLowerCase().contains('change') ?? false));

      final requestBody = _buildRequestBody(request, userProvider, isChangeSiteRequest);

      final response = await ApiManager.instance.post(URLs.submitSiteRequest, body: requestBody);

      if (response.statusCode >= 200 && response.statusCode < 300) {
        _handleSubmitSuccess(response, request);
        return true;
      } else {
        _handleSubmitError(response);
        return false;
      }
    } catch (error) {
      _errorMessage = '$_errorSubmitFailed: $error';
      loading = false;
      notifyListeners();
      return false;
    }
  }

  /// Fetches paginated site requests
  Future<void> fetchSiteRequests({
    int? pageSize,
    int? pageNumber,
    bool loadMore = false,
    required UserProvider userProvider,
  }) async {
    final size = pageSize ?? _pageSize;
    final page = pageNumber ?? (loadMore ? _currentPage + 1 : 1);

    if (size <= 0 || page < 1) {
      _errorMessage = 'Invalid pagination parameters';
      notifyListeners();
      return;
    }

    _setLoadingState(loadMore);

    try {
      final response = await ApiManager.instance.post(
        URLs.getSiteRequests,
        body: {
          "pageSize": size,
          "pageNumber": page,
          "userId": getCurrentUserUserId(userProvider),
        },
      );

      if (response.statusCode == 200) {
        _handleFetchSuccess(response, page, size, loadMore);
      } else {
        _errorMessage = _errorFetchFailed;
      }
    } catch (e) {
      _errorMessage = 'Error: ${e.toString()}';
    } finally {
      _resetLoadingState();
    }
  }

  /// Loads more site requests (pagination)
  Future<void> loadMoreSiteRequests({required UserProvider userProvider}) async {
    if (!_hasMoreData || _isLoadingMore) return;
    await fetchSiteRequests(loadMore: true, userProvider: userProvider);
  }

  /// Refreshes site requests (resets to first page)
  Future<void> refreshSiteRequests({required UserProvider userProvider}) async {
    await fetchSiteRequests(pageNumber: 1, pageSize: _pageSize, userProvider: userProvider);
  }

  /// Resets provider state
  void reset() {
    _loading = false;
    _errorMessage = null;
    _requestHistory.clear();
    notifyListeners();
  }

  // Private helper methods

  /// Generic API call handler to reduce duplication
  Future<int> _performApiCall({
    required Future<Response> Function() apiCall,
    required void Function(dynamic) onSuccess,
    required String errorMessage,
  }) async {
    _loading = true;
    _errorMessage = null;
    notifyListeners();

    try {
      final response = await apiCall();
      stateCode = response.statusCode;

      if (response.statusCode >= 200 && response.statusCode < 300) {
        final responseData = json.decode(response.body);
        onSuccess(responseData);
      } else {
        _errorMessage = errorMessage;
      }

      _loading = false;
      notifyListeners();
      return response.statusCode;
    } catch (error) {
      _loading = false;
      stateCode = -1;
      _errorMessage = errorMessage;
      notifyListeners();
      return -1;
    }
  }

  Map<String, dynamic> _buildRequestBody(
    SiteRequestModel request,
    UserProvider userProvider,
    bool isChangeSiteRequest,
  ) {
    final siteIdsArray = request.siteIds.asMap().entries.map((entry) {
      final index = entry.key;
      return {
        "id": 0,
        "siteId": int.tryParse(request.siteIds[index]) ?? 0,
        "siteName": request.siteNames[index],
        "oldSiteId": (isChangeSiteRequest && request.oldSiteIds != null && index < request.oldSiteIds!.length) ? int.tryParse(request.oldSiteIds![index]) ?? 0 : 0,
        "oldSitName": (isChangeSiteRequest && request.oldSiteNames != null && index < request.oldSiteNames!.length) ? request.oldSiteNames![index] : ""
      };
    }).toList();

    final departmentIdsArray = (request.departmentIds != null && request.departmentIds!.isNotEmpty)
        ? request.departmentIds!.asMap().entries.map((entry) {
            return {
              "id": 0,
              "departmentId": int.tryParse(request.departmentIds![entry.key]) ?? 0,
              "departmentName": request.departmentNames![entry.key],
            };
          }).toList()
        : [];

    return {
      "id": 0,
      "userId": getCurrentUserUserId(userProvider),
      "requestTypeId": int.tryParse(request.requestType) ?? 0,
      "siteIds": siteIdsArray,
      "departmentIds": departmentIdsArray,
    };
  }

  void _handleSubmitSuccess(Response response, SiteRequestModel request) {
    try {
      final responseData = json.decode(response.body);
      final requestWithId = request.copyWith(
        id: responseData['id']?.toString() ?? 'REQ_${DateTime.now().millisecondsSinceEpoch}',
        status: responseData['status']?.toString() ?? 'Pending',
        requestDate: DateTime.now(),
      );
      _requestHistory.insert(0, requestWithId);
    } catch (e) {
      _errorMessage = 'Request submitted but failed to parse response';
    } finally {
      loading = false;
      notifyListeners();
    }
  }

  void _handleSubmitError(Response response) {
    try {
      final errorData = json.decode(response.body);
      _errorMessage = errorData['message'] ?? _errorSubmitFailed;
    } catch (e) {
      _errorMessage = _errorSubmitFailed;
    }
    loading = false;
    notifyListeners();
  }

  void _setLoadingState(bool loadMore) {
    if (loadMore) {
      _isLoadingMore = true;
    } else {
      loading = true;
      _currentPage = 1;
      _hasMoreData = true;
      _requestHistory.clear();
    }
    _errorMessage = null;
    notifyListeners();
  }

  void _handleFetchSuccess(Response response, int page, int size, bool loadMore) {
    final data = json.decode(response.body);

    if (data['isSuccess'] == true) {
      final siteRequests = (data['data'] as List?)?.map((item) => SiteRequestModel.fromJson(item)).toList() ?? [];

      if (loadMore) {
        _requestHistory.addAll(siteRequests);
      } else {
        _requestHistory.clear();
        _requestHistory.addAll(siteRequests);
      }

      _currentPage = page;
      _hasMoreData = siteRequests.length >= size;
    } else {
      _errorMessage = data['message'] ?? _errorFetchFailed;
    }
  }

  void _resetLoadingState() {
    loading = false;
    _isLoadingMore = false;
    notifyListeners();
  }
}
