import 'dart:async';
import 'dart:typed_data';

import 'package:kasy_kit/core/data/api/base_api_exceptions.dart';
import 'package:kasy_kit/core/data/api/http_client.dart';
import 'package:kasy_kit/core/data/entities/upload_result.dart';
import 'package:kasy_kit/environnements.dart';
import 'package:dio/dio.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:logger/logger.dart';

final storageApiProvider = Provider<StorageApi>(
  (ref) => HttpStorageApi(
    client: ref.read(httpClientProvider),
    environment: ref.watch(environmentProvider),
  ),
);

abstract class StorageApi {
  /// Upload bytes to remote storage and stream upload progress.
  Stream<UploadResult> uploadData(
    Uint8List data,
    String folder,
    String filename, {
    String? mimeType,
    bool isPublic = true,
  });

  /// Delete a file at [imagePath] from remote storage.
  Future<void> deleteFile(String? imagePath);
}

/// HTTP-based storage implementation for a custom REST backend.
///
/// Expected endpoints:
///   POST   /storage/upload  — multipart/form-data with fields: file, folder, public
///   DELETE /storage/file    — JSON body: { "path": "<imagePath>" }
///
/// Expected upload response JSON:
///   { "path": "folder/filename.jpg", "url": "https://..." }
class HttpStorageApi extends StorageApi {
  final HttpClient _client;
  final Environment _environment;
  final Logger _logger = Logger();

  HttpStorageApi({
    required HttpClient client,
    required Environment environment,
  })  : _client = client,
        _environment = environment;

  @override
  Stream<UploadResult> uploadData(
    Uint8List data,
    String folder,
    String filename, {
    String? mimeType,
    bool isPublic = true,
  }) async* {
    try {
      yield UploadResultProgress(0.0);

      final formData = FormData.fromMap({
        'file': MultipartFile.fromBytes(
          data,
          filename: filename,
          contentType: mimeType != null && mimeType.contains('/')
              ? DioMediaType(
                  mimeType.split('/')[0],
                  mimeType.split('/')[1],
                )
              : null,
        ),
        'folder': folder,
        'public': isPublic.toString(),
      });

      final response = await _client.post<Map<String, dynamic>>(
        '/storage/upload',
        data: formData,
      );

      final imagePath =
          response.data?['path'] as String? ?? '$folder/$filename';
      final imagePublicUrl = response.data?['url'] as String? ??
          '${_environment.backendUrl}/storage/$folder/$filename';

      yield UploadResultCompleted(
        imagePath: imagePath,
        imagePublicUrl: isPublic ? imagePublicUrl : '',
      );
    } on DioException catch (e, stackTrace) {
      _logger.e('Storage upload error', error: e, stackTrace: stackTrace);
      throw ApiError.fromDioException(e);
    } catch (e, stackTrace) {
      _logger.e('Storage upload error', error: e, stackTrace: stackTrace);
      throw ApiError(code: 0, message: '$e');
    }
  }

  @override
  Future<void> deleteFile(String? imagePath) async {
    if (imagePath == null || imagePath.isEmpty) return;
    try {
      await _client.delete<void>(
        '/storage/file',
        data: {'path': imagePath},
      );
    } on DioException catch (e, stackTrace) {
      _logger.e('Storage delete error', error: e, stackTrace: stackTrace);
      throw ApiError.fromDioException(e);
    } catch (e, stackTrace) {
      _logger.e('Storage delete error', error: e, stackTrace: stackTrace);
      throw ApiError(code: 0, message: '$e');
    }
  }
}
