import 'package:get/get.dart';
import 'package:marco/helpers/services/app_logger.dart';
import 'package:marco/helpers/services/api_service.dart';
import 'package:marco/controller/project_controller.dart';
import 'package:marco/model/dashboard/project_progress_model.dart';

class DashboardController extends GetxController {
  // =========================
  // Attendance overview
  // =========================
  final RxList<Map<String, dynamic>> roleWiseData =
      <Map<String, dynamic>>[].obs;
  final RxString attendanceSelectedRange = '15D'.obs;
  final RxBool attendanceIsChartView = true.obs;
  final RxBool isAttendanceLoading = false.obs;

  // =========================
  // Project progress overview
  // =========================
  final RxList<ChartTaskData> projectChartData = <ChartTaskData>[].obs;
  final RxString projectSelectedRange = '15D'.obs;
  final RxBool projectIsChartView = true.obs;
  final RxBool isProjectLoading = false.obs;

  // =========================
  // Projects overview
  // =========================
  final RxInt totalProjects = 0.obs;
  final RxInt ongoingProjects = 0.obs;
  final RxBool isProjectsLoading = false.obs;

  // =========================
  // Tasks overview
  // =========================
  final RxInt totalTasks = 0.obs;
  final RxInt completedTasks = 0.obs;
  final RxBool isTasksLoading = false.obs;

  // =========================
  // Teams overview
  // =========================
  final RxInt totalEmployees = 0.obs;
  final RxInt inToday = 0.obs;
  final RxBool isTeamsLoading = false.obs;

  // Common ranges
  final List<String> ranges = ['7D', '15D', '30D'];

  // Inject ProjectController
  final ProjectController projectController = Get.find<ProjectController>();

  @override
  void onInit() {
    super.onInit();

    logSafe(
      'DashboardController initialized with project ID: ${projectController.selectedProjectId.value}',
      level: LogLevel.info,
    );

    fetchAllDashboardData();

    // React to project change
    ever<String>(projectController.selectedProjectId, (id) {
      fetchAllDashboardData();
    });

    // React to range changes
    ever(attendanceSelectedRange, (_) => fetchRoleWiseAttendance());
    ever(projectSelectedRange, (_) => fetchProjectProgress());
  }

  // =========================
  // Helper Methods
  // =========================
  int _getDaysFromRange(String range) {
    switch (range) {
      case '7D':
        return 7;
      case '15D':
        return 15;
      case '30D':
        return 30;
      case '3M':
        return 90;
      case '6M':
        return 180;
      default:
        return 7;
    }
  }

  int getAttendanceDays() => _getDaysFromRange(attendanceSelectedRange.value);
  int getProjectDays() => _getDaysFromRange(projectSelectedRange.value);

  void updateAttendanceRange(String range) {
    attendanceSelectedRange.value = range;
    logSafe('Attendance range updated to $range', level: LogLevel.debug);
  }

  void updateProjectRange(String range) {
    projectSelectedRange.value = range;
    logSafe('Project range updated to $range', level: LogLevel.debug);
  }

  void toggleAttendanceChartView(bool isChart) {
    attendanceIsChartView.value = isChart;
    logSafe('Attendance chart view toggled to: $isChart',
        level: LogLevel.debug);
  }

  void toggleProjectChartView(bool isChart) {
    projectIsChartView.value = isChart;
    logSafe('Project chart view toggled to: $isChart', level: LogLevel.debug);
  }

  // =========================
  // Manual Refresh Methods
  // =========================
  Future<void> refreshDashboard() async {
    logSafe('Manual dashboard refresh triggered.', level: LogLevel.debug);
    await fetchAllDashboardData();
  }

  Future<void> refreshAttendance() async => fetchRoleWiseAttendance();
  Future<void> refreshTasks() async {
    final projectId = projectController.selectedProjectId.value;
    if (projectId.isNotEmpty) await fetchDashboardTasks(projectId: projectId);
  }

  Future<void> refreshProjects() async => fetchProjectProgress();

  // =========================
  // Fetch All Dashboard Data
  // =========================
  Future<void> fetchAllDashboardData() async {
    final String projectId = projectController.selectedProjectId.value;

    if (projectId.isEmpty) {
      logSafe('No project selected. Skipping dashboard API calls.',
          level: LogLevel.warning);
      return;
    }

    await Future.wait([
      fetchRoleWiseAttendance(),
      fetchProjectProgress(),
      fetchDashboardTasks(projectId: projectId),
      fetchDashboardTeams(projectId: projectId),
    ]);
  }

  // =========================
  // API Calls
  // =========================
  Future<void> fetchRoleWiseAttendance() async {
    final String projectId = projectController.selectedProjectId.value;
    if (projectId.isEmpty) return;

    try {
      isAttendanceLoading.value = true;
      final List<dynamic>? response =
          await ApiService.getDashboardAttendanceOverview(
              projectId, getAttendanceDays());

      if (response != null) {
        roleWiseData.value =
            response.map((e) => Map<String, dynamic>.from(e)).toList();
        logSafe('Attendance overview fetched successfully.',
            level: LogLevel.info);
      } else {
        roleWiseData.clear();
        logSafe('Failed to fetch attendance overview: response is null.',
            level: LogLevel.error);
      }
    } catch (e, st) {
      roleWiseData.clear();
      logSafe('Error fetching attendance overview',
          level: LogLevel.error, error: e, stackTrace: st);
    } finally {
      isAttendanceLoading.value = false;
    }
  }

  Future<void> fetchProjectProgress() async {
    final String projectId = projectController.selectedProjectId.value;
    if (projectId.isEmpty) return;

    try {
      isProjectLoading.value = true;
      final response = await ApiService.getProjectProgress(
          projectId: projectId, days: getProjectDays());

      if (response != null && response.success) {
        projectChartData.value =
            response.data.map((d) => ChartTaskData.fromProjectData(d)).toList();
        logSafe('Project progress data mapped for chart', level: LogLevel.info);
      } else {
        projectChartData.clear();
        logSafe('Failed to fetch project progress', level: LogLevel.error);
      }
    } catch (e, st) {
      projectChartData.clear();
      logSafe('Error fetching project progress',
          level: LogLevel.error, error: e, stackTrace: st);
    } finally {
      isProjectLoading.value = false;
    }
  }

  Future<void> fetchDashboardTasks({required String projectId}) async {
    if (projectId.isEmpty) return;

    try {
      isTasksLoading.value = true;
      final response = await ApiService.getDashboardTasks(projectId: projectId);

      if (response != null && response.success) {
        totalTasks.value = response.data?.totalTasks ?? 0;
        completedTasks.value = response.data?.completedTasks ?? 0;
        logSafe('Dashboard tasks fetched', level: LogLevel.info);
      } else {
        totalTasks.value = 0;
        completedTasks.value = 0;
        logSafe('Failed to fetch tasks', level: LogLevel.error);
      }
    } catch (e, st) {
      totalTasks.value = 0;
      completedTasks.value = 0;
      logSafe('Error fetching tasks',
          level: LogLevel.error, error: e, stackTrace: st);
    } finally {
      isTasksLoading.value = false;
    }
  }

  Future<void> fetchDashboardTeams({required String projectId}) async {
    if (projectId.isEmpty) return;

    try {
      isTeamsLoading.value = true;
      final response = await ApiService.getDashboardTeams(projectId: projectId);

      if (response != null && response.success) {
        totalEmployees.value = response.data?.totalEmployees ?? 0;
        inToday.value = response.data?.inToday ?? 0;
        logSafe('Dashboard teams fetched', level: LogLevel.info);
      } else {
        totalEmployees.value = 0;
        inToday.value = 0;
        logSafe('Failed to fetch teams', level: LogLevel.error);
      }
    } catch (e, st) {
      totalEmployees.value = 0;
      inToday.value = 0;
      logSafe('Error fetching teams',
          level: LogLevel.error, error: e, stackTrace: st);
    } finally {
      isTeamsLoading.value = false;
    }
  }
}
