/*
 * Copyright 2023 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import 'package:proxypin/network/channel/channel_context.dart';
import 'package:proxypin/network/http/h2/frame.dart';
import 'package:proxypin/network/util/byte_buf.dart';

class StreamSetting {
  /// 允许发送方通知远程端点用于解码头块的头压缩表的最大大小（以八位字节为单位）。
  /// 初始值为4096个八位字节。
  int headTableSize = 4096;

  ///如果一个端点接收到的这个参数设置为0，它就不能发送PUSH_PROMISE帧。
  ///初始值为1，表示允许服务器推送。
  bool enablePush = true;

  ///指示发送方允许的最大并发流数。这个限制是定向的：它适用于发送方允许接收方创建的流的数量。最初，对该值没有限制。建议此值不小于100，以免不必要地限制并行性。
  int? maxConcurrentStreams;

  /// 指示发送方用于流级流控制的初始窗口大小（以八位字节为单位）。初始值为216-1（65，535）个八位字节。
  int initialWindowSize = 65535;

  ///表示发送方愿意接收的最大帧有效负载的大小（以八位字节为单位）。
  int maxFrameSize = 16384;

  ///建议设置通知对等方发送方准备接受的头列表的最大大小（以八位字节为单位）。
  ///该值基于头字段的未压缩大小，包括名称和值的长度（以八位字节为单位）加上每个头字段32个八位字节的开销。
  int? maxHeaderListSize;
}

class SettingHandler {
  static void handleSettingsFrame(ChannelContext channelContext, FrameHeader frameHeader, ByteBuf payload) {
    // SETTINGS frames must have a length that is a multiple of 6 bytes
    if (frameHeader.length % 6 != 0) {
      throw Exception("Invalid SETTINGS frame length");
    }

    // If the SETTINGS frame has the ACK flag set, then it is an acknowledgement
    if (frameHeader.hasAckFlag) {
      // Handle SETTINGS ACK
      return;
    }
    var setting = channelContext.setting ??= StreamSetting();
    // Otherwise, it is a SETTINGS frame that carries settings
    while (payload.isReadable()) {
      int identifier = payload.readShort();
      int value = payload.readInt();
      // print("SettingHandler.handleSettingsFrame identifier=$identifier value=$value");

      // Handle the setting based on its identifier
      switch (identifier) {
        case 1: // SETTINGS_HEADER_TABLE_SIZE
          setting.headTableSize = value;
          break;
        case 2: // SETTINGS_ENABLE_PUSH
          setting.enablePush = value == 1;
          break;
        case 3: // SETTINGS_MAX_CONCURRENT_STREAMS
          setting.maxConcurrentStreams = value;
          break;
        case 4: // SETTINGS_INITIAL_WINDOW_SIZE
          setting.initialWindowSize = value;
          break;
        case 5: // SETTINGS_MAX_FRAME_SIZE
          setting.maxFrameSize = value;
          break;
        case 6: // SETTINGS_MAX_HEADER_LIST_SIZE
          setting.maxHeaderListSize = value;
        default:
          break;
      }
    }
  }
}
