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

import 'package:on_field_work/helpers/services/app_logger.dart';
import 'package:on_field_work/model/user_permission.dart';
import 'package:on_field_work/model/employees/employee_info.dart';
import 'package:on_field_work/model/projects_model.dart';
import 'package:on_field_work/helpers/services/storage/local_storage.dart';
import 'package:on_field_work/helpers/services/auth_service.dart';
import 'package:on_field_work/helpers/services/api_endpoints.dart';

class PermissionService {
  // In-memory cache keyed by user token
  static final Map<String, Map<String, dynamic>> _userDataCache = {};
  static const String _baseUrl = ApiEndpoints.baseUrl;

  /// Fetches all user-related data (permissions, employee info, projects).
  /// Uses in-memory cache for repeated token queries during session.
  static Future<Map<String, dynamic>> fetchAllUserData(
    String token, {
    bool hasRetried = false,
  }) async {
    logSafe("Fetching user data...");

    // Check for cached data before network request
    final cached = _userDataCache[token];
    if (cached != null) {
      logSafe("User data cache hit.");
      return cached;
    }

    final uri = Uri.parse("$_baseUrl/user/profile");
    final headers = {'Authorization': 'Bearer $token'};

    try {
      final response = await http.get(uri, headers: headers);
      final statusCode = response.statusCode;

      if (statusCode == 200) {
        final raw = json.decode(response.body);
        final data = raw['data'] as Map<String, dynamic>;

        final result = {
          'permissions': _parsePermissions(data['featurePermissions']),
          'employeeInfo': _parseEmployeeInfo(data['employeeInfo']),
          'projects': _parseProjectsInfo(data['projects']),
        };

        _userDataCache[token] = result; // Cache it for future use
        logSafe("User data fetched successfully.");
        return result;
      }

      // Token expired, try refresh once then redirect on failure
      if (statusCode == 401 && !hasRetried) {
        logSafe("Unauthorized. Attempting token refresh...", level: LogLevel.warning);

        final refreshed = await AuthService.refreshToken();
        if (refreshed) {
          final newToken = await LocalStorage.getJwtToken();
          if (newToken != null && newToken.isNotEmpty) {
            return fetchAllUserData(newToken, hasRetried: true);
          }
        }

        await _handleUnauthorized();
        logSafe("Token refresh failed. Redirecting to login.", level: LogLevel.warning);
        throw Exception('Unauthorized. Token refresh failed.');
      }

      final errorMsg = json.decode(response.body)['message'] ?? 'Unknown error';
      logSafe("Failed to fetch user data: $errorMsg", level: LogLevel.warning);
      throw Exception('Failed to fetch user data: $errorMsg');
    } catch (e, stacktrace) {
      logSafe("Exception while fetching user data", level: LogLevel.error, error: e, stackTrace: stacktrace);
      rethrow; // Let the caller handle or report
    }
  }

  /// Handles unauthorized/user sign out flow
  static Future<void> _handleUnauthorized() async {
    logSafe("Clearing tokens and redirecting to login due to unauthorized access.", level: LogLevel.warning);
    await LocalStorage.removeToken('jwt_token');
    await LocalStorage.removeToken('refresh_token');
    await LocalStorage.setLoggedInUser(false);
    Get.offAllNamed('/auth/login-option');
  }

  /// Robust model parsing for permissions
  static List<UserPermission> _parsePermissions(List<dynamic> permissions) {
    logSafe("Parsing user permissions...");
    return permissions
        .map((perm) => UserPermission.fromJson({'id': perm}))
        .toList();
  }

  /// Robust model parsing for employee info
  static EmployeeInfo _parseEmployeeInfo(Map<String, dynamic>? data) {
    logSafe("Parsing employee info...");
    if (data == null) throw Exception("Employee data missing");
    return EmployeeInfo.fromJson(data);
  }

  /// Robust model parsing for projects list
  static List<ProjectInfo> _parseProjectsInfo(List<dynamic>? projects) {
    logSafe("Parsing projects info...");
    if (projects == null) return [];
    return projects.map((proj) => ProjectInfo.fromJson(proj)).toList();
  }
}
