package com.castlabs.reactnative.playerview;

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.castlabs.reactnative.player.Player;
import com.castlabs.reactnative.R;
import java.util.Map;
import java.util.UUID;

/**
 * The playback view.
 */
@SuppressLint("ViewConstructor")
public class PlayerView extends FrameLayout {
  public final @NonNull String id;

  private final @NonNull Map<String, Player> playerInstanceManager;
  private final @NonNull com.castlabs.android.player.PlayerView delegate;

  private @Nullable String playerInstanceId;

  /**
   * Initializes the player view component.
   *
   * @param context the context
   * @param attrs the attributes
   * @param playerInstanceManager the global player instance manager
   */
  public PlayerView(
      @NonNull Context context,
      @Nullable AttributeSet attrs,
      @NonNull Map<String, Player> playerInstanceManager
  ) {
    super(context, attrs);

    this.id = UUID.randomUUID().toString();
    this.playerInstanceManager = playerInstanceManager;

    FrameLayout mainView = (FrameLayout) View.inflate(getContext(), R.layout.view_video, null);
    this.delegate = mainView.findViewById(R.id.playerView);
    addView(mainView);

    delegate.setKeepScreenOn(true);
  }

  /**
   * Attaches this view to the given player.
   * If this view is already attached to another player, it detaches it first.
   *
   * @param newPlayerId The player UUID
   */
  public void setPlayerId(String newPlayerId) {
    detachFromCurrentPlayer();
    playerInstanceId = newPlayerId;
    Player player = playerInstanceManager.get(newPlayerId);
    if (player != null) {
      player.playerViewInstanceId = id;
      delegate.setPlayerController(player.getDelegate());
      delegate.prepareSurface();
      measureAndLayout();
      player.onPlayerViewCreated(this);
    }
  }

  @NonNull
  public com.castlabs.android.player.PlayerView getDelegate() {
    return delegate;
  }

  public void release() {
    Player player = playerInstanceManager.get(playerInstanceId);
    if (player != null) {
      player.onPlayerViewWillDestroy(this);
    }

    detachFromCurrentPlayer();
  }

  /**
   * Updates the layout with new measurements.
   */
  public void measureAndLayout() {
    post(() -> {
      measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY),
          MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.EXACTLY));
      layout(getLeft(), getTop(), getRight(), getBottom());
    });
  }

  private void detachFromCurrentPlayer() {
    delegate.setKeepScreenOn(false);

    Player player = playerInstanceManager.get(playerInstanceId);
    if (player != null) {
      synchronized (player) {
        delegate.removeSurface();
        delegate.setPlayerController(null);
      }
      player.playerViewInstanceId = null;
    } else {
      delegate.removeSurface();
      delegate.setPlayerController(null);
    }

    playerInstanceId = null;
  }
}
