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/api/storage_api.dart';
import 'package:kasy_kit/core/data/entities/upload_result.dart';
import 'package:kasy_kit/core/data/entities/user_entity.dart';
import 'package:dio/dio.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

final userApiProvider = Provider<UserApi>(
  (ref) => UserApi(
    client: ref.read(httpClientProvider),
    storageApi: ref.read(storageApiProvider),
  ),
);

class UserApi {
  final HttpClient _client;
  final StorageApi _storageApi;

  UserApi({
    required HttpClient client,
    required StorageApi storageApi,
  })  : _client = client,
        _storageApi = storageApi;

  Future<UserEntity?> get(String id) async {
    try {
      final response = await _client.get(
        '/users/$id',
      );
      if (response.data == null) {
        return null;
      }
      return UserEntity.fromJson(response.data! as Map<String, dynamic>);
    } on DioException catch (e) {
      throw ApiError.fromDioException(e);
    } catch (e, stacktrace) {
      throw ApiError(
        code: 0,
        message: '$e: $stacktrace',
      );
    }
  }

  Future<void> update(UserEntity user) async {
    try {
      final data = user.toJson()..removeWhere((_, v) => v == null);
      final _ = await _client.put(
        '/users/${user.id}',
        data: data,
      );
    } on DioException catch (e) {
      throw ApiError.fromDioException(e);
    } catch (e, stacktrace) {
      throw ApiError(
        code: 0,
        message: '$e: $stacktrace',
      );
    }
  }

  Future<void> delete(String userId) async {
    try {
      final _ = await _client.delete(
        '/users/$userId',
      );
    } on DioException catch (e) {
      throw ApiError.fromDioException(e);
    } catch (e, stacktrace) {
      throw ApiError(
        code: 0,
        message: '$e: $stacktrace',
      );
    }
  }

  Future<void> deleteMe() async {
    try {
      final _ = await _client.delete(
        '/users/me',
      );
    } on DioException catch (e) {
      throw ApiError.fromDioException(e);
    } catch (e, stacktrace) {
      throw ApiError(
        code: 0,
        message: '$e: $stacktrace',
      );
    }
  }

  Future<void> create(UserEntity user) async {
    try {
      final _ = await _client.post(
        '/users/${user.id}',
        data: user.toJson(),
      );
    } on DioException catch (e) {
      throw ApiError.fromDioException(e);
    } catch (e, stacktrace) {
      throw ApiError(
        code: 0,
        message: '$e: $stacktrace',
      );
    }
  }

  Stream<UploadResult> updateAvatar(
    String userId,
    Uint8List data,
  ) async* {
    final task = _storageApi.uploadData(
      data,
      'users/$userId/avatar',
      'thumb.jpg',
      mimeType: 'image/jpg',
    );
    await for (final res in task) {
      if (res case UploadResultCompleted()) {
        await update(UserEntity(id: userId, avatarPath: res.imagePublicUrl));
      }
      yield res;
    }
  }

  Future<void> deleteAvatar(String userId) async {
    await _storageApi.deleteFile('users/$userId/avatar/thumb.jpg');
    await update(UserEntity(id: userId, avatarPath: ''));
  }

  Future<void> updateLocale(String userId, String locale) async {
    try {
      final _ = await _client.put(
        '/users/$userId/locale',
        data: {'locale': locale},
      );
    } on DioException catch (e) {
      throw ApiError.fromDioException(e);
    } catch (e, stacktrace) {
      throw ApiError(
        code: 0,
        message: '$e: $stacktrace',
      );
    }
  }
}
