/*
 * Copyright 2020 The Android Open Source Project
 *
 * 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
 *
 *      http://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.
 */
package androidx.media3.demo.main;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;

import android.content.Intent;
import android.net.Uri;
import androidx.annotation.Nullable;
import androidx.media3.common.C;
import androidx.media3.common.MediaItem;
import androidx.media3.common.MediaItem.ClippingConfiguration;
import androidx.media3.common.MediaItem.SubtitleConfiguration;
import androidx.media3.common.MediaMetadata;
import androidx.media3.common.util.Util;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/** Util to read from and populate an intent. */
public class IntentUtil {

  // Actions.

  public static final String ACTION_VIEW = "androidx.media3.demo.main.action.VIEW";
  public static final String ACTION_VIEW_LIST = "androidx.media3.demo.main.action.VIEW_LIST";

  // Activity extras.
  public static final String PREFER_EXTENSION_DECODERS_EXTRA = "prefer_extension_decoders";

  // Media item configuration extras.

  public static final String URI_EXTRA = "uri";
  public static final String TITLE_EXTRA = "title";
  public static final String MIME_TYPE_EXTRA = "mime_type";
  public static final String CLIP_START_POSITION_MS_EXTRA = "clip_start_position_ms";
  public static final String CLIP_END_POSITION_MS_EXTRA = "clip_end_position_ms";

  public static final String AD_TAG_URI_EXTRA = "ad_tag_uri";

  public static final String DRM_SCHEME_EXTRA = "drm_scheme";
  public static final String DRM_LICENSE_URI_EXTRA = "drm_license_uri";
  public static final String DRM_KEY_REQUEST_PROPERTIES_EXTRA = "drm_key_request_properties";
  public static final String DRM_SESSION_FOR_CLEAR_CONTENT = "drm_session_for_clear_content";
  public static final String DRM_MULTI_SESSION_EXTRA = "drm_multi_session";
  public static final String DRM_FORCE_DEFAULT_LICENSE_URI_EXTRA = "drm_force_default_license_uri";

  public static final String SUBTITLE_URI_EXTRA = "subtitle_uri";
  public static final String SUBTITLE_MIME_TYPE_EXTRA = "subtitle_mime_type";
  public static final String SUBTITLE_LANGUAGE_EXTRA = "subtitle_language";

  /** Creates a list of {@link MediaItem media items} from an {@link Intent}. */
  public static List<MediaItem> createMediaItemsFromIntent(Intent intent) {
    List<MediaItem> mediaItems = new ArrayList<>();
    if (ACTION_VIEW_LIST.equals(intent.getAction())) {
      int index = 0;
      while (intent.hasExtra(URI_EXTRA + "_" + index)) {
        Uri uri = Uri.parse(intent.getStringExtra(URI_EXTRA + "_" + index));
        mediaItems.add(createMediaItemFromIntent(uri, intent, /* extrasKeySuffix= */ "_" + index));
        index++;
      }
    } else {
      Uri uri = intent.getData();
      mediaItems.add(createMediaItemFromIntent(uri, intent, /* extrasKeySuffix= */ ""));
    }
    return mediaItems;
  }

  /** Populates the intent with the given list of {@link MediaItem media items}. */
  public static void addToIntent(List<MediaItem> mediaItems, Intent intent) {
    checkArgument(!mediaItems.isEmpty());
    if (mediaItems.size() == 1) {
      MediaItem mediaItem = mediaItems.get(0);
      MediaItem.LocalConfiguration localConfiguration = checkNotNull(mediaItem.localConfiguration);
      intent.setAction(ACTION_VIEW).setData(mediaItem.localConfiguration.uri);
      if (mediaItem.mediaMetadata.title != null) {
        intent.putExtra(TITLE_EXTRA, mediaItem.mediaMetadata.title);
      }
      addPlaybackPropertiesToIntent(localConfiguration, intent, /* extrasKeySuffix= */ "");
      addClippingConfigurationToIntent(
          mediaItem.clippingConfiguration, intent, /* extrasKeySuffix= */ "");
    } else {
      intent.setAction(ACTION_VIEW_LIST);
      for (int i = 0; i < mediaItems.size(); i++) {
        MediaItem mediaItem = mediaItems.get(i);
        MediaItem.LocalConfiguration localConfiguration =
            checkNotNull(mediaItem.localConfiguration);
        intent.putExtra(URI_EXTRA + ("_" + i), localConfiguration.uri.toString());
        addPlaybackPropertiesToIntent(localConfiguration, intent, /* extrasKeySuffix= */ "_" + i);
        addClippingConfigurationToIntent(
            mediaItem.clippingConfiguration, intent, /* extrasKeySuffix= */ "_" + i);
        if (mediaItem.mediaMetadata.title != null) {
          intent.putExtra(TITLE_EXTRA + ("_" + i), mediaItem.mediaMetadata.title);
        }
      }
    }
  }

  private static MediaItem createMediaItemFromIntent(
      Uri uri, Intent intent, String extrasKeySuffix) {
    @Nullable String mimeType = intent.getStringExtra(MIME_TYPE_EXTRA + extrasKeySuffix);
    @Nullable String title = intent.getStringExtra(TITLE_EXTRA + extrasKeySuffix);
    @Nullable String adTagUri = intent.getStringExtra(AD_TAG_URI_EXTRA + extrasKeySuffix);
    @Nullable
    SubtitleConfiguration subtitleConfiguration =
        createSubtitleConfiguration(intent, extrasKeySuffix);
    MediaItem.Builder builder =
        new MediaItem.Builder()
            .setUri(uri)
            .setMimeType(mimeType)
            .setMediaMetadata(new MediaMetadata.Builder().setTitle(title).build())
            .setClippingConfiguration(
                new ClippingConfiguration.Builder()
                    .setStartPositionMs(
                        intent.getLongExtra(CLIP_START_POSITION_MS_EXTRA + extrasKeySuffix, 0))
                    .setEndPositionMs(
                        intent.getLongExtra(
                            CLIP_END_POSITION_MS_EXTRA + extrasKeySuffix, C.TIME_END_OF_SOURCE))
                    .build());
    if (adTagUri != null) {
      builder.setAdsConfiguration(
          new MediaItem.AdsConfiguration.Builder(Uri.parse(adTagUri)).build());
    }
    if (subtitleConfiguration != null) {
      builder.setSubtitleConfigurations(ImmutableList.of(subtitleConfiguration));
    }

    return populateDrmPropertiesFromIntent(builder, intent, extrasKeySuffix).build();
  }

  @Nullable
  private static MediaItem.SubtitleConfiguration createSubtitleConfiguration(
      Intent intent, String extrasKeySuffix) {
    if (!intent.hasExtra(SUBTITLE_URI_EXTRA + extrasKeySuffix)) {
      return null;
    }
    return new MediaItem.SubtitleConfiguration.Builder(
            Uri.parse(intent.getStringExtra(SUBTITLE_URI_EXTRA + extrasKeySuffix)))
        .setMimeType(
            checkNotNull(intent.getStringExtra(SUBTITLE_MIME_TYPE_EXTRA + extrasKeySuffix)))
        .setLanguage(intent.getStringExtra(SUBTITLE_LANGUAGE_EXTRA + extrasKeySuffix))
        .setSelectionFlags(C.SELECTION_FLAG_DEFAULT)
        .build();
  }

  private static MediaItem.Builder populateDrmPropertiesFromIntent(
      MediaItem.Builder builder, Intent intent, String extrasKeySuffix) {
    String schemeKey = DRM_SCHEME_EXTRA + extrasKeySuffix;
    @Nullable String drmSchemeExtra = intent.getStringExtra(schemeKey);
    if (drmSchemeExtra == null) {
      return builder;
    }
    Map<String, String> headers = new HashMap<>();
    @Nullable
    String[] keyRequestPropertiesArray =
        intent.getStringArrayExtra(DRM_KEY_REQUEST_PROPERTIES_EXTRA + extrasKeySuffix);
    if (keyRequestPropertiesArray != null) {
      for (int i = 0; i < keyRequestPropertiesArray.length; i += 2) {
        headers.put(keyRequestPropertiesArray[i], keyRequestPropertiesArray[i + 1]);
      }
    }
    @Nullable UUID drmUuid = Util.getDrmUuid(drmSchemeExtra);
    if (drmUuid != null) {
      builder.setDrmConfiguration(
          new MediaItem.DrmConfiguration.Builder(drmUuid)
              .setLicenseUri(intent.getStringExtra(DRM_LICENSE_URI_EXTRA + extrasKeySuffix))
              .setMultiSession(
                  intent.getBooleanExtra(DRM_MULTI_SESSION_EXTRA + extrasKeySuffix, false))
              .setForceDefaultLicenseUri(
                  intent.getBooleanExtra(
                      DRM_FORCE_DEFAULT_LICENSE_URI_EXTRA + extrasKeySuffix, false))
              .setLicenseRequestHeaders(headers)
              .setForceSessionsForAudioAndVideoTracks(
                  intent.getBooleanExtra(DRM_SESSION_FOR_CLEAR_CONTENT + extrasKeySuffix, false))
              .build());
    }
    return builder;
  }

  private static void addPlaybackPropertiesToIntent(
      MediaItem.LocalConfiguration localConfiguration, Intent intent, String extrasKeySuffix) {
    intent
        .putExtra(MIME_TYPE_EXTRA + extrasKeySuffix, localConfiguration.mimeType)
        .putExtra(
            AD_TAG_URI_EXTRA + extrasKeySuffix,
            localConfiguration.adsConfiguration != null
                ? localConfiguration.adsConfiguration.adTagUri.toString()
                : null);
    if (localConfiguration.drmConfiguration != null) {
      addDrmConfigurationToIntent(localConfiguration.drmConfiguration, intent, extrasKeySuffix);
    }
    if (!localConfiguration.subtitleConfigurations.isEmpty()) {
      checkState(localConfiguration.subtitleConfigurations.size() == 1);
      MediaItem.SubtitleConfiguration subtitleConfiguration =
          localConfiguration.subtitleConfigurations.get(0);
      intent.putExtra(SUBTITLE_URI_EXTRA + extrasKeySuffix, subtitleConfiguration.uri.toString());
      intent.putExtra(SUBTITLE_MIME_TYPE_EXTRA + extrasKeySuffix, subtitleConfiguration.mimeType);
      intent.putExtra(SUBTITLE_LANGUAGE_EXTRA + extrasKeySuffix, subtitleConfiguration.language);
    }
  }

  private static void addDrmConfigurationToIntent(
      MediaItem.DrmConfiguration drmConfiguration, Intent intent, String extrasKeySuffix) {
    intent.putExtra(DRM_SCHEME_EXTRA + extrasKeySuffix, drmConfiguration.scheme.toString());
    intent.putExtra(
        DRM_LICENSE_URI_EXTRA + extrasKeySuffix,
        drmConfiguration.licenseUri != null ? drmConfiguration.licenseUri.toString() : null);
    intent.putExtra(DRM_MULTI_SESSION_EXTRA + extrasKeySuffix, drmConfiguration.multiSession);
    intent.putExtra(
        DRM_FORCE_DEFAULT_LICENSE_URI_EXTRA + extrasKeySuffix,
        drmConfiguration.forceDefaultLicenseUri);

    String[] drmKeyRequestProperties =
        new String[drmConfiguration.licenseRequestHeaders.size() * 2];
    int index = 0;
    for (Map.Entry<String, String> entry : drmConfiguration.licenseRequestHeaders.entrySet()) {
      drmKeyRequestProperties[index++] = entry.getKey();
      drmKeyRequestProperties[index++] = entry.getValue();
    }
    intent.putExtra(DRM_KEY_REQUEST_PROPERTIES_EXTRA + extrasKeySuffix, drmKeyRequestProperties);

    List<@C.TrackType Integer> forcedDrmSessionTrackTypes =
        drmConfiguration.forcedSessionTrackTypes;
    if (!forcedDrmSessionTrackTypes.isEmpty()) {
      // Only video and audio together are supported.
      checkState(
          forcedDrmSessionTrackTypes.size() == 2
              && forcedDrmSessionTrackTypes.contains(C.TRACK_TYPE_VIDEO)
              && forcedDrmSessionTrackTypes.contains(C.TRACK_TYPE_AUDIO));
      intent.putExtra(DRM_SESSION_FOR_CLEAR_CONTENT + extrasKeySuffix, true);
    }
  }

  private static void addClippingConfigurationToIntent(
      MediaItem.ClippingConfiguration clippingConfiguration,
      Intent intent,
      String extrasKeySuffix) {
    if (clippingConfiguration.startPositionMs != 0) {
      intent.putExtra(
          CLIP_START_POSITION_MS_EXTRA + extrasKeySuffix, clippingConfiguration.startPositionMs);
    }
    if (clippingConfiguration.endPositionMs != C.TIME_END_OF_SOURCE) {
      intent.putExtra(
          CLIP_END_POSITION_MS_EXTRA + extrasKeySuffix, clippingConfiguration.endPositionMs);
    }
  }
}
