/// Submissions Repository Implementation
///
/// Implements the submissions repository interface with caching support.
library;

import 'package:worker/features/projects/data/datasources/project_progress_local_datasource.dart';
import 'package:worker/features/projects/data/datasources/project_status_local_datasource.dart';
import 'package:worker/features/projects/data/datasources/submissions_remote_datasource.dart';
import 'package:worker/features/projects/data/models/project_submission_request.dart';
import 'package:worker/features/projects/domain/entities/project_progress.dart';
import 'package:worker/features/projects/domain/entities/project_status.dart';
import 'package:worker/features/projects/domain/entities/project_submission.dart';
import 'package:worker/features/projects/domain/repositories/submissions_repository.dart';

/// Submissions Repository Implementation
///
/// Handles data operations for project submissions with cache-first pattern.
class SubmissionsRepositoryImpl implements SubmissionsRepository {
  const SubmissionsRepositoryImpl(
    this._remoteDataSource,
    this._statusLocalDataSource,
    this._progressLocalDataSource,
  );

  final SubmissionsRemoteDataSource _remoteDataSource;
  final ProjectStatusLocalDataSource _statusLocalDataSource;
  final ProjectProgressLocalDataSource _progressLocalDataSource;

  /// Get project status list with cache-first pattern
  ///
  /// 1. Return cached data if available
  /// 2. Fetch from API in background and update cache
  /// 3. If no cache, wait for API response
  @override
  Future<List<ProjectStatus>> getProjectStatusList({
    bool forceRefresh = false,
  }) async {
    // Check cache first (unless force refresh)
    if (!forceRefresh && _statusLocalDataSource.hasCachedData()) {
      final cachedStatuses = _statusLocalDataSource.getCachedStatusList();
      if (cachedStatuses.isNotEmpty) {
        // Return cached data immediately
        // Also refresh cache in background (fire and forget)
        _refreshStatusCache();
        return cachedStatuses.map((model) => model.toEntity()).toList();
      }
    }

    // No cache or force refresh - fetch from API
    try {
      final statusModels = await _remoteDataSource.getProjectStatusList();

      // Cache the result
      await _statusLocalDataSource.cacheStatusList(statusModels);

      return statusModels.map((model) => model.toEntity()).toList();
    } catch (e) {
      // If API fails, try to return cached data as fallback
      final cachedStatuses = _statusLocalDataSource.getCachedStatusList();
      if (cachedStatuses.isNotEmpty) {
        return cachedStatuses.map((model) => model.toEntity()).toList();
      }
      rethrow;
    }
  }

  /// Refresh status cache in background
  Future<void> _refreshStatusCache() async {
    try {
      final statusModels = await _remoteDataSource.getProjectStatusList();
      await _statusLocalDataSource.cacheStatusList(statusModels);
    } catch (e) {
      // Silently fail - we already returned cached data
    }
  }

  /// Get project progress list with cache-first pattern
  ///
  /// 1. Return cached data if available
  /// 2. Fetch from API in background and update cache
  /// 3. If no cache, wait for API response
  @override
  Future<List<ProjectProgress>> getProjectProgressList({
    bool forceRefresh = false,
  }) async {
    // Check cache first (unless force refresh)
    if (!forceRefresh && _progressLocalDataSource.hasCachedData()) {
      final cachedProgress = _progressLocalDataSource.getCachedProgressList();
      if (cachedProgress.isNotEmpty) {
        // Return cached data immediately
        // Also refresh cache in background (fire and forget)
        _refreshProgressCache();
        return cachedProgress.map((model) => model.toEntity()).toList();
      }
    }

    // No cache or force refresh - fetch from API
    try {
      final progressModels = await _remoteDataSource.getProjectProgressList();

      // Cache the result
      await _progressLocalDataSource.cacheProgressList(progressModels);

      return progressModels.map((model) => model.toEntity()).toList();
    } catch (e) {
      // If API fails, try to return cached data as fallback
      final cachedProgress = _progressLocalDataSource.getCachedProgressList();
      if (cachedProgress.isNotEmpty) {
        return cachedProgress.map((model) => model.toEntity()).toList();
      }
      rethrow;
    }
  }

  /// Refresh progress cache in background
  Future<void> _refreshProgressCache() async {
    try {
      final progressModels = await _remoteDataSource.getProjectProgressList();
      await _progressLocalDataSource.cacheProgressList(progressModels);
    } catch (e) {
      // Silently fail - we already returned cached data
    }
  }

  @override
  Future<List<ProjectSubmission>> getSubmissions({
    int limitStart = 0,
    int limitPageLength = 0,
  }) async {
    try {
      final submissionModels = await _remoteDataSource.getSubmissions(
        limitStart: limitStart,
        limitPageLength: limitPageLength,
      );
      return submissionModels.map((model) => model.toEntity()).toList();
    } catch (e) {
      rethrow;
    }
  }

  @override
  Future<ProjectSubmission> getSubmissionDetail(String name) async {
    try {
      final model = await _remoteDataSource.getSubmissionDetail(name);
      return model.toEntity();
    } catch (e) {
      rethrow;
    }
  }

  @override
  Future<String> saveSubmission(ProjectSubmissionRequest request) async {
    try {
      return await _remoteDataSource.saveSubmission(request);
    } catch (e) {
      rethrow;
    }
  }

  @override
  Future<String> uploadProjectFile({
    required String projectName,
    required String filePath,
  }) async {
    try {
      return await _remoteDataSource.uploadProjectFile(
        projectName: projectName,
        filePath: filePath,
      );
    } catch (e) {
      rethrow;
    }
  }

  @override
  Future<void> deleteProjectFile({
    required String fileId,
    required String projectName,
  }) async {
    try {
      return await _remoteDataSource.deleteProjectFile(
        fileId: fileId,
        projectName: projectName,
      );
    } catch (e) {
      rethrow;
    }
  }
}
