import 'dart:convert';

import 'package:http/http.dart' as http;
import 'package:logging/logging.dart';
import 'package:result_monad/result_monad.dart';

import '../friendica_client/paged_response.dart';
import '../globals.dart';
import '../models/exec_error.dart';

final _logger = Logger('NetworkUtils');

http.Response requestTimeout() => http.Response('Client side timeout', 408);

FutureResult<PagedResponse<String>, ExecError> getUrl(
  Uri url, {
  Map<String, String>? headers,
  Duration? timeout,
}) async {
  _logger.fine('GET: $url');
  final requestHeaders = headers ?? {};
  if (usePhpDebugging) {
    requestHeaders['Cookie'] = 'XDEBUG_SESSION=PHPSTORM;path=/';
  }
  try {
    final request = http.get(
      url,
      headers: requestHeaders,
    );

    final response = await request.timeout(
      timeout ?? apiCallTimeout,
      onTimeout: requestTimeout,
    );

    if (response.statusCode != 200) {
      return Result.error(ExecError(
          type: ErrorType.authentication,
          message: '${response.statusCode}: ${response.reasonPhrase}'));
    }
    return PagedResponse.fromLinkHeader(
      response.headers['link'],
      utf8.decode(response.bodyBytes),
    );
  } catch (e) {
    return Result.error(
        ExecError(type: ErrorType.localError, message: e.toString()));
  }
}

FutureResult<String, ExecError> postUrl(
  Uri url,
  Map<String, dynamic> body, {
  Map<String, String>? headers,
  Duration? timeout,
}) async {
  _logger.fine('POST: $url \n Body: $body');
  final requestHeaders = headers ?? {};
  if (usePhpDebugging) {
    requestHeaders['Cookie'] = 'XDEBUG_SESSION=PHPSTORM;path=/';
  }
  try {
    final request = http.post(
      url,
      headers: requestHeaders,
      body: jsonEncode(body),
    );

    final response = await request.timeout(
      timeout ?? apiCallTimeout,
      onTimeout: requestTimeout,
    );

    if (response.statusCode != 200) {
      return Result.error(ExecError(
          type: ErrorType.authentication,
          message: '${response.statusCode}: ${response.reasonPhrase}'));
    }
    return Result.ok(utf8.decode(response.bodyBytes));
  } catch (e) {
    return Result.error(
        ExecError(type: ErrorType.localError, message: e.toString()));
  }
}

FutureResult<String, ExecError> putUrl(
  Uri url,
  Map<String, dynamic> body, {
  Map<String, String>? headers,
}) async {
  _logger.fine('PUT: $url \n Body: $body');
  try {
    final request = http.put(
      url,
      headers: headers,
      body: jsonEncode(body),
    );

    final response = await request.timeout(
      apiCallTimeout,
      onTimeout: requestTimeout,
    );

    if (response.statusCode != 200) {
      return Result.error(ExecError(
          type: ErrorType.authentication,
          message: '${response.statusCode}: ${response.reasonPhrase}'));
    }
    return Result.ok(utf8.decode(response.bodyBytes));
  } catch (e) {
    return Result.error(
        ExecError(type: ErrorType.localError, message: e.toString()));
  }
}

FutureResult<String, ExecError> deleteUrl(
  Uri url,
  Map<String, dynamic> body, {
  Map<String, String>? headers,
}) async {
  _logger.fine('DELETE: $url');
  try {
    final request = http.delete(
      url,
      headers: headers,
      body: jsonEncode(body),
    );

    final response = await request.timeout(
      apiCallTimeout,
      onTimeout: requestTimeout,
    );

    if (response.statusCode != 200) {
      return Result.error(ExecError(
          type: ErrorType.authentication,
          message: '${response.statusCode}: ${response.reasonPhrase}'));
    }
    return Result.ok(utf8.decode(response.bodyBytes));
  } catch (e) {
    return Result.error(
        ExecError(type: ErrorType.localError, message: e.toString()));
  }
}
