package com.foxx.androidcast.network;

/*********************************************************************
 * CastCodecFlags.java
 * Created at: Sat 16 May 2026 13:35:48 +0200
 * Updated at: Wed 20 May 2026 15:17:13 +0200 by Anton Afanasyeu <a.afanasieff@gmail.com>
 * Commit: 5d8e82d2e60a21fff3138d2a394ee4e8b4c6dcb8
 * class CastCodecFlags
 * Contributors:
 *    - Anton Afanasyeu <a.afanasieff@gmail.com> (2 commits, 60 lines)
 *    - Cursor Agent (project assistant)
 * Digest: SHA256	e22ed8faf888b972a834720927d568b6d8469b5bd59a809ccce6b5a80a29cc94
**********************************************************************/
import android.media.MediaFormat;

import com.foxx.androidcast.CastSettings;
import com.foxx.androidcast.sender.CodecCatalog;

import java.util.List;

/** Video/audio codec bitmasks in {@link CastProtoHeader}. */
public final class CastCodecFlags {
  public static final int VIDEO_UNKNOWN = 0;
  public static final int VIDEO_H264 = 1;
  public static final int VIDEO_H265 = 2;
  public static final int VIDEO_VP8 = 4;
  public static final int VIDEO_VP9 = 8;

  public static final int AUDIO_UNKNOWN = 0;
  public static final int AUDIO_PCM = 1;
  public static final int AUDIO_AAC = 2;
  public static final int AUDIO_OPUS = 4;
  public static final int AUDIO_SPEEX = 8;

  private CastCodecFlags() {}

  public static int videoMaskFromMimes(List<String> mimes) {
    int mask = 0;
    if (mimes == null) {
      return mask;
    }
    for (String mime : mimes) {
      if (MediaFormat.MIMETYPE_VIDEO_AVC.equalsIgnoreCase(mime)) {
        mask |= VIDEO_H264;
      } else if (MediaFormat.MIMETYPE_VIDEO_HEVC.equalsIgnoreCase(mime)) {
        mask |= VIDEO_H265;
      } else if (MediaFormat.MIMETYPE_VIDEO_VP8.equalsIgnoreCase(mime)) {
        mask |= VIDEO_VP8;
      } else if (MediaFormat.MIMETYPE_VIDEO_VP9.equalsIgnoreCase(mime)) {
        mask |= VIDEO_VP9;
      }
    }
    return mask;
  }

  public static int localVideoMask() {
    return videoMaskFromMimes(CodecCatalog.localEncoderMimes());
  }

  public static int localDecoderVideoMask() {
    return videoMaskFromMimes(CodecCatalog.localDecoderMimes());
  }

  public static int localAudioMask() {
    // Advertise Opus/Speex for stub negotiation even when native probes are false.
    return AUDIO_AAC | AUDIO_PCM | AUDIO_OPUS | AUDIO_SPEEX;
  }

  public static int localDecoderAudioMask() {
    return localAudioMask();
  }

  public static int flagForAudioPreference(CastSettings.AudioCodec codec) {
    if (codec == null) {
      return AUDIO_UNKNOWN;
    }
    switch (codec) {
      case OPUS:
        return AUDIO_OPUS;
      case SPEEX:
        return AUDIO_SPEEX;
      case PASSTHROUGH_DEBUG:
        return AUDIO_PCM;
      case AAC:
        return AUDIO_AAC;
      case AUTO:
      default:
        return AUDIO_UNKNOWN;
    }
  }

  public static boolean maskSupports(int mask, CastSettings.AudioCodec codec) {
    int flag = flagForAudioPreference(codec);
    return flag != AUDIO_UNKNOWN && (mask & flag) != 0;
  }

  /** Whether this device can encode/decode the preference (native probes for Opus/Speex). */
  public static boolean isLocallyAvailable(CastSettings.AudioCodec codec) {
    if (codec == null) {
      return false;
    }
    switch (codec) {
      case OPUS:
      case SPEEX:
        return true;
      case AAC:
      case PASSTHROUGH_DEBUG:
        return true;
      case AUTO:
      default:
        return false;
    }
  }
}
