/// Providers: Project Submissions
///
/// Riverpod providers for managing project submissions state.
library;

import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:worker/core/network/dio_client.dart';
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/data/repositories/submissions_repository_impl.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';

part 'submissions_provider.g.dart';

/// Project Status Local Data Source Provider
@riverpod
ProjectStatusLocalDataSource projectStatusLocalDataSource(Ref ref) {
  return ProjectStatusLocalDataSource();
}

/// Project Progress Local Data Source Provider
@riverpod
ProjectProgressLocalDataSource projectProgressLocalDataSource(Ref ref) {
  return ProjectProgressLocalDataSource();
}

/// Submissions Remote Data Source Provider
@riverpod
Future<SubmissionsRemoteDataSource> submissionsRemoteDataSource(Ref ref) async {
  final dioClient = await ref.watch(dioClientProvider.future);
  return SubmissionsRemoteDataSourceImpl(dioClient);
}

/// Submissions Repository Provider
@riverpod
Future<SubmissionsRepository> submissionsRepository(Ref ref) async {
  final remoteDataSource = await ref.watch(submissionsRemoteDataSourceProvider.future);
  final statusLocalDataSource = ref.watch(projectStatusLocalDataSourceProvider);
  final progressLocalDataSource = ref.watch(projectProgressLocalDataSourceProvider);
  return SubmissionsRepositoryImpl(
    remoteDataSource,
    statusLocalDataSource,
    progressLocalDataSource,
  );
}

/// Project Status List Provider
///
/// Fetches project status options from API with cache-first pattern.
/// This is loaded before submissions to ensure filter options are available.
@riverpod
class ProjectStatusList extends _$ProjectStatusList {
  @override
  Future<List<ProjectStatus>> build() async {
    final repository = await ref.watch(submissionsRepositoryProvider.future);
    return repository.getProjectStatusList();
  }

  /// Refresh status list from remote (force refresh)
  Future<void> refresh() async {
    state = const AsyncValue.loading();
    state = await AsyncValue.guard(() async {
      final repository = await ref.read(submissionsRepositoryProvider.future);
      return repository.getProjectStatusList(forceRefresh: true);
    });
  }
}

/// Project Progress List Provider
///
/// Fetches construction progress stages from API with cache-first pattern.
/// Used for dropdown selection when creating/updating project submissions.
@riverpod
class ProjectProgressList extends _$ProjectProgressList {
  @override
  Future<List<ProjectProgress>> build() async {
    final repository = await ref.watch(submissionsRepositoryProvider.future);
    return repository.getProjectProgressList();
  }

  /// Refresh progress list from remote (force refresh)
  Future<void> refresh() async {
    state = const AsyncValue.loading();
    state = await AsyncValue.guard(() async {
      final repository = await ref.read(submissionsRepositoryProvider.future);
      return repository.getProjectProgressList(forceRefresh: true);
    });
  }
}

/// All Submissions Provider
///
/// Fetches and manages submissions data from remote.
/// Waits for project status list and progress list to be loaded first.
@riverpod
class AllSubmissions extends _$AllSubmissions {
  @override
  Future<List<ProjectSubmission>> build() async {
    // Ensure status list and progress list are loaded first (for filter options)
    await ref.watch(projectStatusListProvider.future);
    await ref.watch(projectProgressListProvider.future);

    // Then fetch submissions
    final repository = await ref.watch(submissionsRepositoryProvider.future);
    return repository.getSubmissions();
  }

  /// Refresh submissions from remote
  Future<void> refresh() async {
    state = const AsyncValue.loading();
    state = await AsyncValue.guard(() async {
      // Also refresh status list and progress list
      await ref.read(projectStatusListProvider.notifier).refresh();
      await ref.read(projectProgressListProvider.notifier).refresh();

      final repository = await ref.read(submissionsRepositoryProvider.future);
      return repository.getSubmissions();
    });
  }
}

/// Submissions Filter State
///
/// Manages search and status filter state.
/// Status filter uses the status label string from API (e.g., "Chờ phê duyệt").
@riverpod
class SubmissionsFilter extends _$SubmissionsFilter {
  @override
  ({String searchQuery, String? selectedStatus}) build() {
    return (searchQuery: '', selectedStatus: null);
  }

  /// Update search query
  void updateSearchQuery(String query) {
    state = (searchQuery: query, selectedStatus: state.selectedStatus);
  }

  /// Select a status filter (uses Vietnamese label from API)
  void selectStatus(String? status) {
    state = (searchQuery: state.searchQuery, selectedStatus: status);
  }

  /// Clear status filter
  void clearStatusFilter() {
    state = (searchQuery: state.searchQuery, selectedStatus: null);
  }

  /// Clear search query
  void clearSearchQuery() {
    state = (searchQuery: '', selectedStatus: state.selectedStatus);
  }

  /// Clear all filters
  void clearAllFilters() {
    state = (searchQuery: '', selectedStatus: null);
  }
}

/// Filtered Submissions Provider
///
/// Combines submissions data with filter state to return filtered results.
@riverpod
AsyncValue<List<ProjectSubmission>> filteredSubmissions(Ref ref) {
  final dataAsync = ref.watch(allSubmissionsProvider);
  final filter = ref.watch(submissionsFilterProvider);

  return dataAsync.whenData((submissions) {
    var filtered = submissions;

    // Filter by status (matches Vietnamese label from API)
    if (filter.selectedStatus != null) {
      filtered = filtered.where((s) => s.status == filter.selectedStatus).toList();
    }

    // Filter by search query
    if (filter.searchQuery.isNotEmpty) {
      final query = filter.searchQuery.toLowerCase();
      filtered = filtered.where((s) {
        return s.submissionId.toLowerCase().contains(query) ||
            s.designedArea.toLowerCase().contains(query);
      }).toList();
    }

    // Sort by request date (newest first)
    filtered.sort((a, b) => b.requestDate.compareTo(a.requestDate));

    return filtered;
  });
}

/// Submission Detail Provider
///
/// Fetches full project detail by name for editing.
/// Uses family modifier to cache by submission name.
@riverpod
Future<ProjectSubmission> submissionDetail(Ref ref, String name) async {
  final repository = await ref.watch(submissionsRepositoryProvider.future);
  return repository.getSubmissionDetail(name);
}

/// Save Submission Provider
///
/// Handles creating new project submissions via API.
@riverpod
class SaveSubmission extends _$SaveSubmission {
  @override
  AsyncValue<void> build() {
    return const AsyncValue.data(null);
  }

  /// Save a new project submission
  ///
  /// Returns the project name (ID) if successful, throws exception on failure.
  Future<String> save(ProjectSubmissionRequest request) async {
    state = const AsyncValue.loading();
    try {
      final repository = await ref.read(submissionsRepositoryProvider.future);
      if (!ref.mounted) throw Exception('Provider disposed');

      final projectName = await repository.saveSubmission(request);
      if (!ref.mounted) return projectName;

      state = const AsyncValue.data(null);

      // Refresh submissions list after successful save
      ref.invalidate(allSubmissionsProvider);

      return projectName;
    } catch (e, st) {
      if (ref.mounted) {
        state = AsyncValue.error(e, st);
      }
      rethrow;
    }
  }
}

/// Upload state for tracking individual file uploads
class FileUploadState {
  final String filePath;
  final bool isUploading;
  final bool isUploaded;
  final String? fileUrl;
  final String? error;

  const FileUploadState({
    required this.filePath,
    this.isUploading = false,
    this.isUploaded = false,
    this.fileUrl,
    this.error,
  });

  FileUploadState copyWith({
    bool? isUploading,
    bool? isUploaded,
    String? fileUrl,
    String? error,
  }) {
    return FileUploadState(
      filePath: filePath,
      isUploading: isUploading ?? this.isUploading,
      isUploaded: isUploaded ?? this.isUploaded,
      fileUrl: fileUrl ?? this.fileUrl,
      error: error,
    );
  }
}

/// Upload Project Files Provider
///
/// Handles uploading multiple files for a project submission.
/// Tracks upload state for each file individually.
@riverpod
class UploadProjectFiles extends _$UploadProjectFiles {
  @override
  List<FileUploadState> build() {
    return [];
  }

  /// Initialize with file paths
  void initFiles(List<String> filePaths) {
    state = filePaths
        .map((path) => FileUploadState(filePath: path))
        .toList();
  }

  /// Upload all files for a project
  /// Returns list of uploaded file URLs
  Future<List<String>> uploadAll(String projectName) async {
    final uploadedUrls = <String>[];

    for (var i = 0; i < state.length; i++) {
      if (!ref.mounted) break;

      // Mark as uploading
      state = [
        ...state.sublist(0, i),
        state[i].copyWith(isUploading: true),
        ...state.sublist(i + 1),
      ];

      try {
        final repository = await ref.read(submissionsRepositoryProvider.future);
        if (!ref.mounted) break;

        final fileUrl = await repository.uploadProjectFile(
          projectName: projectName,
          filePath: state[i].filePath,
        );

        if (!ref.mounted) break;

        // Mark as uploaded
        state = [
          ...state.sublist(0, i),
          state[i].copyWith(
            isUploading: false,
            isUploaded: true,
            fileUrl: fileUrl,
          ),
          ...state.sublist(i + 1),
        ];

        uploadedUrls.add(fileUrl);
      } catch (e) {
        if (!ref.mounted) break;

        // Mark as failed
        state = [
          ...state.sublist(0, i),
          state[i].copyWith(
            isUploading: false,
            error: e.toString(),
          ),
          ...state.sublist(i + 1),
        ];
      }
    }

    return uploadedUrls;
  }

  /// Clear all files
  void clear() {
    state = [];
  }
}
