import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:on_field_work/helpers/services/app_logger.dart';
import 'package:on_field_work/helpers/services/api_service.dart';
import 'package:on_field_work/model/project_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';

class DailyTaskController extends GetxController {
  List<ProjectModel> projects = [];
  String? selectedProjectId;

  DateTime? startDateTask;
  DateTime? endDateTask;

  // Rx fields for DateRangePickerWidget
  Rx<DateTime> startDateTaskRx = DateTime.now().obs;
  Rx<DateTime> endDateTaskRx = DateTime.now().obs;

  List<TaskModel> dailyTasks = [];
  final RxSet<String> expandedDates = <String>{}.obs;

  void toggleDate(String dateKey) {
    if (expandedDates.contains(dateKey)) {
      expandedDates.remove(dateKey);
    } else {
      expandedDates.add(dateKey);
    }
  }

  RxSet<String> selectedBuildings = <String>{}.obs;
  RxSet<String> selectedFloors = <String>{}.obs;
  RxSet<String> selectedActivities = <String>{}.obs;
  RxSet<String> selectedServices = <String>{}.obs;

  RxBool isFilterLoading = false.obs;
  RxBool isLoading = true.obs;
  RxBool isLoadingMore = false.obs;
  Map<String, List<TaskModel>> groupedDailyTasks = {};

  // Pagination
  int currentPage = 1;
  int pageSize = 20;
  bool hasMore = true;

  FilterData? taskFilterData;

  @override
  void onInit() {
    super.onInit();
    _initializeDefaults();
    _initializeRxDates();
  }

  void _initializeDefaults() {
    _setDefaultDateRange();
  }

  void _setDefaultDateRange() {
    final today = DateTime.now();
    startDateTask = today.subtract(const Duration(days: 7));
    endDateTask = today;

    logSafe(
      "Default date range set: $startDateTask to $endDateTask",
      level: LogLevel.info,
    );
  }

  void _initializeRxDates() {
    startDateTaskRx.value =
        startDateTask ?? DateTime.now().subtract(const Duration(days: 7));
    endDateTaskRx.value = endDateTask ?? DateTime.now();
  }

  void clearTaskFilters() {
    selectedBuildings.clear();
    selectedFloors.clear();
    selectedActivities.clear();
    selectedServices.clear();
    startDateTask = null;
    endDateTask = null;

    // reset Rx dates as well
    startDateTaskRx.value = DateTime.now().subtract(const Duration(days: 7));
    endDateTaskRx.value = DateTime.now();

    update();
  }

  void updateDateRange(DateTime? start, DateTime? end) {
    if (start != null && end != null) {
      startDateTask = start;
      endDateTask = end;

      startDateTaskRx.value = start;
      endDateTaskRx.value = end;

      update();
    }
  }

  Future<void> fetchTaskData(
    String projectId, {
    int pageNumber = 1,
    int pageSize = 20,
    bool isLoadMore = false,
  }) async {
    if (!isLoadMore) {
      isLoading.value = true;
      currentPage = 1;
      hasMore = true;
      groupedDailyTasks.clear();
      dailyTasks.clear();
    } else {
      isLoadingMore.value = true;
    }

    // Create the filter object
    final filter = {
      "buildingIds": selectedBuildings.toList(),
      "floorIds": selectedFloors.toList(),
      "activityIds": selectedActivities.toList(),
      "serviceIds": selectedServices.toList(),
      "dateFrom": startDateTask?.toIso8601String(),
      "dateTo": endDateTask?.toIso8601String(),
    };

    final response = await ApiService.getDailyTasks(
      projectId,
      filter: filter,
      pageNumber: pageNumber,
      pageSize: pageSize,
    );

    if (response != null && response.isNotEmpty) {
      if (!isLoadMore) {
        groupedDailyTasks.clear();
      }

      for (var task in response) {
        final assignmentDateKey =
            task.assignmentDate.toIso8601String().split('T')[0];

        // Initialize list if not present
        groupedDailyTasks.putIfAbsent(assignmentDateKey, () => []);

        // Only add task if it doesn't already exist (avoid duplicates)
        if (!groupedDailyTasks[assignmentDateKey]!
            .any((t) => t.id == task.id)) {
          groupedDailyTasks[assignmentDateKey]!.add(task);
        }
      }

      dailyTasks = groupedDailyTasks.values.expand((list) => list).toList();
      currentPage = pageNumber;
    } else {
      hasMore = false;
    }

    isLoading.value = false;
    isLoadingMore.value = false;

    update();
  }

  Future<void> fetchTaskFilter(String projectId) async {
    isFilterLoading.value = true;
    try {
      final filterResponse = await ApiService.getDailyTaskFilter(projectId);

      if (filterResponse != null && filterResponse.success) {
        taskFilterData = filterResponse.data;
        logSafe(
          "Task filter fetched successfully. Buildings: ${taskFilterData?.buildings.length}, Floors: ${taskFilterData?.floors.length}",
          level: LogLevel.info,
        );
      } else {
        logSafe(
          "Failed to fetch task filter for projectId: $projectId",
          level: LogLevel.warning,
        );
      }
    } catch (e, stack) {
      logSafe("Exception in fetchTaskFilter: $e", level: LogLevel.error);
      logSafe("StackTrace: $stack", level: LogLevel.debug);
    } finally {
      isFilterLoading.value = false;
      update();
    }
  }

  Future<void> selectDateRangeForTaskData(
    BuildContext context,
    DailyTaskController controller,
  ) async {
    final picked = await showDateRangePicker(
      context: context,
      firstDate: DateTime(2022),
      lastDate: DateTime.now(),
      initialDateRange: DateTimeRange(
        start:
            startDateTask ?? DateTime.now().subtract(const Duration(days: 7)),
        end: endDateTask ?? DateTime.now(),
      ),
    );

    if (picked == null) {
      logSafe("Date range picker cancelled by user.", level: LogLevel.debug);
      return;
    }

    startDateTask = picked.start;
    endDateTask = picked.end;

    // update Rx fields as well
    startDateTaskRx.value = picked.start;
    endDateTaskRx.value = picked.end;

    logSafe(
      "Date range selected: $startDateTask to $endDateTask",
      level: LogLevel.info,
    );

    final projectId = controller.selectedProjectId;
    if (projectId != null && projectId.isNotEmpty) {
      await controller.fetchTaskData(projectId);
    } else {
      logSafe("Project ID is null or empty, skipping fetchTaskData",
          level: LogLevel.warning);
    }
  }

  void refreshTasksFromNotification({
    required String projectId,
    required String taskAllocationId,
  }) async {
    await fetchTaskData(projectId);
    update();
  }
}
