import 'dart:io' as io show HttpClient, HttpHeaders;

import 'package:http/http.dart' as http;
import 'package:http/io_client.dart';


const _sessionCookie = 'session_id';

@override
http.Client buildHttpClient() => _SessionClient(IOClient(io.HttpClient()));

class _SessionClient extends http.BaseClient {
  final http.Client _inner;
  String? _sessionId;

  _SessionClient(this._inner);

  @override
  Future<http.StreamedResponse> send(http.BaseRequest request) async {
    if (_sessionId != null) {
      request.headers[io.HttpHeaders.cookieHeader] = '$_sessionCookie=$_sessionId';
    }

    request.followRedirects = false;
    request.maxRedirects = 0;

    http.StreamedResponse response = await _inner.send(request);

    _captureCookie(response.headers[io.HttpHeaders.setCookieHeader]);

    while (response.isRedirect) {
      final location = response.headers['location'];
      if (location == null) break;

      final redirected = http.Request(request.method, Uri.parse(location))
        ..headers.addAll(request.headers)
        ..bodyBytes = await response.stream.toBytes()
        ..followRedirects = false
        ..maxRedirects = 0;

      response = await _inner.send(redirected);
      _captureCookie(response.headers[io.HttpHeaders.setCookieHeader]);
    }

    return response;
  }

  void _captureCookie(String? setCookieHeader) {
    if (setCookieHeader == null) return;
    final match = RegExp('$_sessionCookie=([^;]+)',
            caseSensitive: false)
        .firstMatch(setCookieHeader);
    if (match != null) _sessionId = match.group(1);
  }
}
