import 'package:get/get.dart';
import 'package:marco/helpers/services/app_logger.dart';
import 'package:marco/helpers/services/api_service.dart';
import 'package:marco/helpers/widgets/my_form_validator.dart';
import 'package:marco/helpers/widgets/my_snackbar.dart';
import 'package:marco/model/project_model.dart';
import 'package:marco/model/dailyTaskPlanning/daily_task_planning_model.dart';
import 'package:marco/model/employees/employee_model.dart';

class DailyTaskPlanningController extends GetxController {
  List<ProjectModel> projects = [];
  List<EmployeeModel> employees = [];
  List<TaskPlanningDetailsModel> dailyTasks = [];

  RxMap<String, RxBool> uploadingStates = <String, RxBool>{}.obs;
  RxList<EmployeeModel> selectedEmployees = <EmployeeModel>[].obs;

  MyFormValidator basicValidator = MyFormValidator();
  List<Map<String, dynamic>> roles = [];
  RxBool isAssigningTask = false.obs;
  RxnString selectedRoleId = RxnString();
  RxBool isLoading = false.obs;

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

  void _initializeDefaults() {
    fetchProjects();
  }

  String? formFieldValidator(String? value, {required String fieldType}) {
    if (value == null || value.trim().isEmpty) {
      return 'This field is required';
    }
    if (fieldType == "target" && int.tryParse(value.trim()) == null) {
      return 'Please enter a valid number';
    }
    if (fieldType == "description" && value.trim().length < 5) {
      return 'Description must be at least 5 characters';
    }
    return null;
  }

  void updateSelectedEmployees() {
    final selected =
        employees.where((e) => uploadingStates[e.id]?.value == true).toList();
    selectedEmployees.value = selected;
    logSafe("Updated selected employees", level: LogLevel.debug);
  }

  void onRoleSelected(String? roleId) {
    selectedRoleId.value = roleId;
    logSafe("Role selected", level: LogLevel.info);
  }

  Future<void> fetchRoles() async {
    logSafe("Fetching roles...", level: LogLevel.info);
    final result = await ApiService.getRoles();
    if (result != null) {
      roles = List<Map<String, dynamic>>.from(result);
      logSafe("Roles fetched successfully", level: LogLevel.info);
      update();
    } else {
      logSafe("Failed to fetch roles", level: LogLevel.error);
    }
  }

  Future<bool> assignDailyTask({
    required String workItemId,
    required int plannedTask,
    required String description,
    required List<String> taskTeam,
    DateTime? assignmentDate,
  }) async {
    isAssigningTask.value = true;
    logSafe("Starting assign task...", level: LogLevel.info);

    final response = await ApiService.assignDailyTask(
      workItemId: workItemId,
      plannedTask: plannedTask,
      description: description,
      taskTeam: taskTeam,
      assignmentDate: assignmentDate,
    );

    isAssigningTask.value = false;

    if (response == true) {
      logSafe("Task assigned successfully", level: LogLevel.info);
      showAppSnackbar(
        title: "Success",
        message: "Task assigned successfully!",
        type: SnackbarType.success,
      );
      return true;
    } else {
      logSafe("Failed to assign task", level: LogLevel.error);
      showAppSnackbar(
        title: "Error",
        message: "Failed to assign task.",
        type: SnackbarType.error,
      );
      return false;
    }
  }

  Future<void> fetchProjects() async {
    isLoading.value = true;
    try {
      final response = await ApiService.getProjects();
      if (response?.isEmpty ?? true) {
        logSafe("No project data found or API call failed",
            level: LogLevel.warning);
        return;
      }

      projects = response!.map((json) => ProjectModel.fromJson(json)).toList();
      logSafe("Projects fetched: ${projects.length} projects loaded",
          level: LogLevel.info);
      update();
    } catch (e, stack) {
      logSafe("Error fetching projects",
          level: LogLevel.error, error: e, stackTrace: stack);
    } finally {
      isLoading.value = false;
    }
  }

  /// Fetch Infra details and then tasks per work area
  Future<void> fetchTaskData(String? projectId, {String? serviceId}) async {
    if (projectId == null) {
      logSafe("Project ID is null", level: LogLevel.warning);
      return;
    }

    isLoading.value = true;
    try {
      // Fetch infra details
      final infraResponse = await ApiService.getInfraDetails(projectId);
      final infraData = infraResponse?['data'] as List<dynamic>?;

      if (infraData == null || infraData.isEmpty) {
        logSafe("No infra data found for project $projectId",
            level: LogLevel.warning);
        dailyTasks = [];
        return;
      }

      // Map infra to dailyTasks structure
      dailyTasks = infraData.map((buildingJson) {
        final building = Building(
          id: buildingJson['id'],
          name: buildingJson['buildingName'],
          description: buildingJson['description'],
          floors: (buildingJson['floors'] as List<dynamic>).map((floorJson) {
            return Floor(
              id: floorJson['id'],
              floorName: floorJson['floorName'],
              workAreas:
                  (floorJson['workAreas'] as List<dynamic>).map((areaJson) {
                return WorkArea(
                  id: areaJson['id'],
                  areaName: areaJson['areaName'],
                  workItems: [], // Will fill after tasks API
                );
              }).toList(),
            );
          }).toList(),
        );

        return TaskPlanningDetailsModel(
          id: building.id,
          name: building.name,
          projectAddress: "",
          contactPerson: "",
          startDate: DateTime.now(),
          endDate: DateTime.now(),
          projectStatusId: "",
          buildings: [building],
        );
      }).toList();

      // Fetch tasks for each work area, passing serviceId only if selected
      await Future.wait(dailyTasks
          .expand((task) => task.buildings)
          .expand((b) => b.floors)
          .expand((f) => f.workAreas)
          .map((area) async {
        try {
          final taskResponse = await ApiService.getWorkItemsByWorkArea(
            area.id,
            // serviceId: serviceId, // <-- only pass if not null
          );
          final taskData = taskResponse?['data'] as List<dynamic>? ?? [];

          area.workItems.addAll(taskData.map((taskJson) {
            return WorkItemWrapper(
              workItemId: taskJson['id'],
              workItem: WorkItem(
                id: taskJson['id'],
                activityMaster: taskJson['activityMaster'] != null
                    ? ActivityMaster.fromJson(taskJson['activityMaster'])
                    : null,
                workCategoryMaster: taskJson['workCategoryMaster'] != null
                    ? WorkCategoryMaster.fromJson(
                        taskJson['workCategoryMaster'])
                    : null,
                plannedWork: (taskJson['plannedWork'] as num?)?.toDouble(),
                completedWork: (taskJson['completedWork'] as num?)?.toDouble(),
                todaysAssigned:
                    (taskJson['todaysAssigned'] as num?)?.toDouble(),
                description: taskJson['description'] as String?,
                taskDate: taskJson['taskDate'] != null
                    ? DateTime.tryParse(taskJson['taskDate'])
                    : null,
              ),
            );
          }));
        } catch (e, stack) {
          logSafe("Error fetching tasks for work area ${area.id}",
              level: LogLevel.error, error: e, stackTrace: stack);
        }
      }));

      logSafe("Fetched infra and tasks for project $projectId",
          level: LogLevel.info);
    } catch (e, stack) {
      logSafe("Error fetching daily task data",
          level: LogLevel.error, error: e, stackTrace: stack);
    } finally {
      isLoading.value = false;
      update();
    }
  }

  Future<void> fetchEmployeesByProject(String? projectId) async {
    if (projectId == null || projectId.isEmpty) {
      logSafe("Project ID is required but was null or empty",
          level: LogLevel.error);
      return;
    }

    isLoading.value = true;
    try {
      final response = await ApiService.getAllEmployeesByProject(projectId);
      if (response != null && response.isNotEmpty) {
        employees =
            response.map((json) => EmployeeModel.fromJson(json)).toList();
        for (var emp in employees) {
          uploadingStates[emp.id] = false.obs;
        }
        logSafe(
          "Employees fetched: ${employees.length} for project $projectId",
          level: LogLevel.info,
        );
      } else {
        employees = [];
        logSafe(
          "No employees found for project $projectId",
          level: LogLevel.warning,
        );
      }
    } catch (e, stack) {
      logSafe(
        "Error fetching employees for project $projectId",
        level: LogLevel.error,
        error: e,
        stackTrace: stack,
      );
    } finally {
      isLoading.value = false;
      update();
    }
  }
}
