// Copyright (C) 2022 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

import 'dart:convert';

import 'package:http/http.dart';
import 'package:wyatt_http_client/src/models/unfreezed_request.dart';
import 'package:wyatt_http_client/src/utils/convert.dart';
import 'package:wyatt_http_client/src/utils/request_utils.dart';

/// {@template middleware_request}
/// A class that represents a middleware request.
/// {@endtemplate}
class MiddlewareRequest {
  /// {@macro middleware_request}
  MiddlewareRequest({
    required this.unfreezedRequest,
  }) : _httpRequest = Request(unfreezedRequest.method, unfreezedRequest.url);

  /// The unfreezed request.
  UnfreezedRequest unfreezedRequest;

  Request _httpRequest;

  /// The http request. (Read-only)
  Request get request => _httpRequest;

  /// The request method (proxy, read-only).
  String get method => _httpRequest.method;

  /// The request url (proxy, read-only).
  Uri get url => _httpRequest.url;

  /// The request headers (proxy, read-only).
  Map<String, String> get headers => _httpRequest.headers;

  /// The request body (proxy, read-only).
  Encoding get encoding => _httpRequest.encoding;

  /// The request body (proxy, read-only).
  String get encodedBody => _httpRequest.body;

  /// The request body (proxy, read-only).
  Object? get body => unfreezedRequest.body;

  /// Copies this request and returns a new request with the given
  /// [unfreezedRequest].
  MiddlewareRequest copyWith({
    UnfreezedRequest? unfreezedRequest,
  }) =>
      MiddlewareRequest(
        unfreezedRequest: unfreezedRequest ?? this.unfreezedRequest,
      );

  /// Modifies the request with the given [unfreezedRequest].
  void modifyRequest(UnfreezedRequest unfreezedRequest) {
    String? body;
    if (unfreezedRequest.body != null) {
      var body = unfreezedRequest.body;
      if (body is String) {
        body = body;
      } else if (body is List) {
        body = String.fromCharCodes(body.cast<int>());
      } else if (body is Map) {
        body = Convert.mapToQuery(body.cast<String, String>());
      }
    }
    _httpRequest = RequestUtils.copyRequestWith(
      _httpRequest,
      method: unfreezedRequest.method,
      url: unfreezedRequest.url,
      headers: unfreezedRequest.headers,
      body: body,
    ) as Request;
    if (unfreezedRequest.encoding != null) {
      _httpRequest.encoding = unfreezedRequest.encoding!;
    }
    this.unfreezedRequest = unfreezedRequest;
  }

  /// Applies the changes made to the request by modifying it with the
  /// [unfreezedRequest].
  void apply() {
    modifyRequest(unfreezedRequest);
  }

  @override
  String toString() => 'MiddlewareRequest(unfreezedRequest: $unfreezedRequest)';
}
