import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:mnemo_cards/managers/repository/repository.dart';
import 'package:mnemo_cards/managers/user_manager.dart';
import 'package:mnemo_cards_common/mnemo_cards_common.dart';

import 'api.dart';

class HttpRepository extends Repository with Api {
  final Dio _dio;

  HttpRepository(this._dio);

  @override
  Future<UserDto> get user async => UserDto.empty;

  @override
  Stream<UserDto> get userStream =>
      Stream.periodic(const Duration(seconds: 5)).map((event) => UserDto.empty);

  @override
  Future<void> updateUser(UserDto dto) async {}

  @override
  Future<(UserDto, String)> createOrGetUser(
    String externalId,
    ExternalIdType idType,
    String? name,
  ) async {
    try {
      final r = await _dio.post<String>('$path/user/create', data: {
        'token': externalId,
        'tokenType': idType.name,
        'name': name,
      });
      //todo add client header encryption ??
      final authToken = r.headers[HttpHeaders.authorizationHeader]!.last;
      return ((r.data as String).decode(UserDto.fromJson), authToken);
    } on DioException catch (e, s) {
      log('User create error', error: e, stackTrace: s);
      rethrow;
    }
  }

  void setAuthToken(String? authToken) {
    _dio.interceptors.add(
      InterceptorsWrapper(onRequest: (options, handler) {
        options.headers[HttpHeaders.authorizationHeader] = authToken;
        handler.next(options);
      }),
    );
  }

  @override
  Future<UserDto?> getUser() async {
    final r = await _dio.get<String>('$path/user');
    if (r.statusCode == 200) {
      return (r.data as String).decode(UserDto.fromJson);
    }
    return null;
  }

  @override
  Future<void> updateUserData(UserDataDto data) async {
    final r = await _dio.post('$path/user/data', data: data.encode());
  }

  @override
  Future<void> updateUserSettings(UserSettingsDto settings) async {
    final r = await _dio.post('$path/user/settings', data: settings.encode());
  }

  @override
  Future<void> addTestStatistics(TestStatisticsDto testStatistics) async {
    final r = await _dio.post(
      '$path/user/data/add/test-statistics',
      data: testStatistics.encode(),
    );
  }

  @override
  Future<List<TestDto>> getTests({String packId = ''}) async {
    final r = await _dio.get<String>(
      '$path/tests/$packId',
    );
    return (r.data as String).decodeList(TestDto.fromJson);
  }

  @override
  Future<TestDto?> getTest(String id) async {
    final r = await _dio.get<String>(
      '$path/test/$id',
    );
    try {
      return (r.data as String).decode(TestDto.fromJson);
    } catch (e, s) {
      log(e.toString(), stackTrace: s);
      return null;
    }
  }

  @override
  Future<bool> checkPayment(
    String itemId,
    String key,
    PaymentSystem paymentSystem,
  ) async {
    final r = await _dio.get<String>(
      '$path/check_payment/',
      queryParameters: {
        'id': itemId,
        'token': key,
        'system': paymentSystem.name,
      },
    );
    return jsonDecode(r.data ?? '{}')['result'] ?? false;
  }

  @override
  Future<bool> checkUserPayment() async {
    final r = await _dio.get<String>('$path/check_payments/');
    final result = jsonDecode(r.data ?? '{}')?['result'] ?? false;
    return result;
  }

  Future<String?> createPayment(String id, PaymentSystem paymentSystem) async {
    final r = await _dio.get(
      '$path/create_payment/',
      queryParameters: {
        'id': id,
        'system': paymentSystem.name,
      },
    );
    return jsonDecode(r.data)?['url'] as String?;
  }
}
