import 'dart:developer';

import 'package:injectable/injectable.dart';
import 'package:data_channel/data_channel.dart';

import '../../../common/api/api_client.dart';
import '../../../common/api/api_failure.dart';
import '../../../common/extension/extension.dart';
import '../../../common/url/api_path.dart';
import '../../../domain/auth/auth.dart';
import '../auth_dtos.dart';

@injectable
class AuthRemoteDataProvider {
  final ApiClient _apiClient;
  final String _logName = "AuthRemoteDataProvider";

  AuthRemoteDataProvider(this._apiClient);

  Future<DC<AuthFailure, CheckPhoneDto>> checkPhone({
    required String phoneNumber,
  }) async {
    try {
      final response = await _apiClient.post(
        ApiPath.checkPhone,
        data: {'phone_number': phoneNumber},
      );

      if (response.data['code'] == 401) {
        return DC.error(
          AuthFailure.serverError(
            ApiFailure.unauthorized('Incorrect email or password'),
          ),
        );
      }

      if (response.data['success'] == false) {
        if ((response.data['errors'] as List).isNotEmpty) {
          if (response.data['errors'][0]['code'] == 303) {
            return DC.error(
              AuthFailure.dynamicErrorMessage('No. Telepon Tidak Boleh Kosong'),
            );
          }
          if (response.data['errors'][0]['code'] == 304) {
            return DC.error(
              AuthFailure.dynamicErrorMessage(
                response.data['errors'][0]['cause'],
              ),
            );
          }
        }
      }

      final dto = CheckPhoneDto.fromJson(response.data['data']);
      return DC.data(dto);
    } on ApiFailure catch (e, s) {
      log('checkPhone', name: _logName, error: e, stackTrace: s);
      return DC.error(AuthFailure.serverError(e));
    }
  }

  Future<DC<AuthFailure, RegisterDto>> register({
    required String phoneNumber,
    required String name,
    required DateTime birthDate,
  }) async {
    try {
      final response = await _apiClient.post(
        ApiPath.register,
        data: {
          'phone_number': phoneNumber,
          'name': name,
          'birth_date': birthDate.toServerDate,
        },
      );

      if (response.data['success'] == false) {
        if ((response.data['errors'] as List).isNotEmpty) {
          if (response.data['errors'][0]['code'] == "900") {
            return DC.error(
              AuthFailure.dynamicErrorMessage('No. Telepon Sudah Terdaftar'),
            );
          } else {
            return DC.error(
              AuthFailure.dynamicErrorMessage(
                'Terjadi kesalahan coba lagi nanti',
              ),
            );
          }
        } else {
          return DC.error(
            AuthFailure.dynamicErrorMessage(
              'Terjadi kesalahan coba lagi nanti',
            ),
          );
        }
      }

      final dto = RegisterDto.fromJson(response.data['data']);
      return DC.data(dto);
    } on ApiFailure catch (e, s) {
      log('register', name: _logName, error: e, stackTrace: s);
      return DC.error(AuthFailure.serverError(e));
    }
  }

  Future<DC<AuthFailure, VerifyDto>> verify({
    required String registrationToken,
    required String otpCode,
  }) async {
    try {
      final response = await _apiClient.post(
        ApiPath.verify,
        data: {'registration_token': registrationToken, 'otp_code': otpCode},
      );

      if (response.data['success'] == false) {
        if ((response.data['errors'] as List).isNotEmpty) {
          if (response.data['errors'][0]['code'] == "900") {
            return DC.error(
              AuthFailure.dynamicErrorMessage('Kode OTP Tidak Sesuai'),
            );
          } else {
            return DC.error(
              AuthFailure.dynamicErrorMessage(
                'Terjadi kesalahan coba lagi nanti',
              ),
            );
          }
        } else {
          return DC.error(
            AuthFailure.dynamicErrorMessage(
              'Terjadi kesalahan coba lagi nanti',
            ),
          );
        }
      }

      final dto = VerifyDto.fromJson(response.data['data']);
      return DC.data(dto);
    } on ApiFailure catch (e, s) {
      log('verify', name: _logName, error: e, stackTrace: s);
      return DC.error(AuthFailure.serverError(e));
    }
  }

  Future<DC<AuthFailure, LoginDto>> setPassword({
    required String registrationToken,
    required String password,
    required String confirmPassword,
  }) async {
    try {
      final response = await _apiClient.post(
        ApiPath.setPassword,
        data: {
          'registration_token': registrationToken,
          'password': password,
          'confirm_password': confirmPassword,
        },
      );

      if (response.data['success'] == false) {
        if ((response.data['errors'] as List).isNotEmpty) {
          if (response.data['errors'][0]['code'] == 900) {
            return DC.error(
              AuthFailure.dynamicErrorMessage(
                'Invalid Registration, Lakukan kembali dari awal',
              ),
            );
          } else if (response.data['errors'][0]['code'] == "304") {
            return DC.error(
              AuthFailure.dynamicErrorMessage(
                response.data['errors'][0]['cause'],
              ),
            );
          } else {
            return DC.error(
              AuthFailure.dynamicErrorMessage(
                'Terjadi kesalahan coba lagi nanti',
              ),
            );
          }
        } else {
          return DC.error(
            AuthFailure.dynamicErrorMessage(
              'Terjadi kesalahan coba lagi nanti',
            ),
          );
        }
      }

      final dto = LoginDto.fromJson(response.data['data']);
      return DC.data(dto);
    } on ApiFailure catch (e, s) {
      log('setPassword', name: _logName, error: e, stackTrace: s);
      return DC.error(AuthFailure.serverError(e));
    }
  }

  Future<DC<AuthFailure, LoginDto>> login({
    required String phoneNumber,
    required String password,
  }) async {
    try {
      final response = await _apiClient.post(
        ApiPath.login,
        data: {'phone_number': phoneNumber, 'password': password},
      );

      if (response.data['success'] == false) {
        if ((response.data['errors'] as List).isNotEmpty) {
          if (response.data['errors'][0]['code'] == "900") {
            return DC.error(
              AuthFailure.dynamicErrorMessage('Kamu Belum Terdaftar'),
            );
          } else {
            return DC.error(
              AuthFailure.dynamicErrorMessage(
                'Terjadi kesalahan coba lagi nanti',
              ),
            );
          }
        } else {
          return DC.error(
            AuthFailure.dynamicErrorMessage(
              'Terjadi kesalahan coba lagi nanti',
            ),
          );
        }
      }

      final dto = LoginDto.fromJson(response.data['data']);
      return DC.data(dto);
    } on ApiFailure catch (e, s) {
      log('login', name: _logName, error: e, stackTrace: s);
      return DC.error(AuthFailure.serverError(e));
    }
  }

  Future<DC<AuthFailure, ResendDto>> resend({
    required String phoneNumber,
    required String purpose, //login or registration
  }) async {
    try {
      final response = await _apiClient.post(
        ApiPath.resend,
        data: {'phone_number': phoneNumber, 'purpose': purpose},
      );

      if (response.data['success'] == false) {
        return DC.error(
          AuthFailure.dynamicErrorMessage('Terjadi kesalahan coba lagi nanti'),
        );
      }

      final dto = ResendDto.fromJson(response.data['data']);
      return DC.data(dto);
    } on ApiFailure catch (e, s) {
      log('resend', name: _logName, error: e, stackTrace: s);
      return DC.error(AuthFailure.serverError(e));
    }
  }
}
