package org.thoughtcrime.securesms.stickers;

import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Point;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar;
import androidx.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;

import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.PassphraseRequiredActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.glide.cache.ApngOptions;
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.sharing.ShareActivity;
import org.thoughtcrime.securesms.stickers.StickerManifest.Sticker;
import org.thoughtcrime.securesms.util.DeviceProperties;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.whispersystems.libsignal.util.Pair;
import org.whispersystems.signalservice.api.util.OptionalUtil;

import java.util.Optional;


/**
 * Shows the contents of a pack and allows the user to install it (if not installed) or remove it
 * (if installed). This is also the handler for sticker pack deep links.
 */
public final class StickerPackPreviewActivity extends PassphraseRequiredActivity
                                              implements StickerRolloverTouchListener.RolloverEventListener,
                                                         StickerRolloverTouchListener.RolloverStickerRetriever,
                                                         StickerPackPreviewAdapter.EventListener
{

  private static final String TAG = Log.tag(StickerPackPreviewActivity.class);

  private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme();

  private StickerPackPreviewViewModel viewModel;

  private ImageView    coverImage;
  private TextView     stickerTitle;
  private TextView     stickerAuthor;
  private View         installButton;
  private View         removeButton;
  private RecyclerView stickerList;
  private View         shareButton;
  private View         shareButtonImage;

  private StickerPackPreviewAdapter    adapter;
  private GridLayoutManager            layoutManager;
  private StickerRolloverTouchListener touchListener;

  public static Intent getIntent(@NonNull String packId, @NonNull String packKey) {
    Intent intent = new Intent(Intent.ACTION_VIEW, StickerUrl.createActionUri(packId, packKey));
    intent.addCategory(Intent.CATEGORY_DEFAULT);
    intent.addCategory(Intent.CATEGORY_BROWSABLE);
    return intent;
  }

  @Override
  protected void onPreCreate() {
    super.onPreCreate();
    dynamicTheme.onCreate(this);
  }

  @Override
  protected void onCreate(Bundle savedInstanceState, boolean ready) {
    setContentView(R.layout.sticker_preview_activity);

    Optional<Pair<String, String>> stickerParams = StickerUrl.parseExternalUri(getIntent().getData());

    if (!stickerParams.isPresent()) {
      Log.w(TAG, "Invalid URI!");
      presentError();
      return;
    }

    String packId  = stickerParams.get().first();
    String packKey = stickerParams.get().second();

    initToolbar();
    initView();
    initViewModel(packId, packKey);
  }

  @Override
  protected void onResume() {
    super.onResume();
    dynamicTheme.onResume(this);
  }

  @Override
  public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    onScreenWidthChanged(getScreenWidth());
  }

  @Override
  public void onStickerLongPress(@NonNull View view) {
    if (touchListener != null) {
      touchListener.enterHoverMode(stickerList, view);
    }
  }

  @Override
  public void onStickerPopupStarted() {
  }

  @Override
  public void onStickerPopupEnded() {
  }

  @Override
  public @Nullable Pair<Object, String> getStickerDataFromView(@NonNull View view) {
    if (stickerList != null) {
      StickerPackPreviewAdapter.StickerViewHolder holder = (StickerPackPreviewAdapter.StickerViewHolder) stickerList.getChildViewHolder(view);
      if (holder != null) {
        return new Pair<>(holder.getCurrentGlideModel(), holder.getCurrentEmoji());
      }
    }
    return null;
  }

  private void initView() {
    this.coverImage       = findViewById(R.id.sticker_install_cover);
    this.stickerTitle     = findViewById(R.id.sticker_install_title);
    this.stickerAuthor    = findViewById(R.id.sticker_install_author);
    this.installButton    = findViewById(R.id.sticker_install_button);
    this.removeButton     = findViewById(R.id.sticker_install_remove_button);
    this.stickerList      = findViewById(R.id.sticker_install_list);
    this.shareButton      = findViewById(R.id.sticker_install_share_button);
    this.shareButtonImage = findViewById(R.id.sticker_install_share_button_image);

    this.adapter       = new StickerPackPreviewAdapter(GlideApp.with(this), this, DeviceProperties.shouldAllowApngStickerAnimation(this));
    this.layoutManager = new GridLayoutManager(this, 2);
    this.touchListener = new StickerRolloverTouchListener(this, GlideApp.with(this), this, this);
    onScreenWidthChanged(getScreenWidth());

    stickerList.setLayoutManager(layoutManager);
    stickerList.addOnItemTouchListener(touchListener);
    stickerList.setAdapter(adapter);
  }

  private void initToolbar() {
    Toolbar toolbar = findViewById(R.id.sticker_install_toolbar);

    setSupportActionBar(toolbar);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    getSupportActionBar().setTitle(R.string.StickerPackPreviewActivity_stickers);

    toolbar.setNavigationOnClickListener(v -> onBackPressed());
  }

  private void initViewModel(@NonNull String packId, @NonNull String packKey) {
    viewModel = ViewModelProviders.of(this, new StickerPackPreviewViewModel.Factory(getApplication(),
                                                                                    new StickerPackPreviewRepository(this),
                                                                                    new StickerManagementRepository(this)))
                                  .get(StickerPackPreviewViewModel.class);

    viewModel.getStickerManifest(packId, packKey).observe(this, manifest -> {
      if (manifest == null) return;

      if (manifest.isPresent()) {
        presentManifest(manifest.get().getManifest());
        presentButton(manifest.get().isInstalled());
        presentShareButton(manifest.get().isInstalled(), manifest.get().getManifest().getPackId(), manifest.get().getManifest().getPackKey());
      } else {
        presentError();
      }
    });
  }

  private void presentManifest(@NonNull StickerManifest manifest) {
    stickerTitle.setText(manifest.getTitle().orElse(getString(R.string.StickerPackPreviewActivity_untitled)));
    stickerAuthor.setText(manifest.getAuthor().orElse(getString(R.string.StickerPackPreviewActivity_unknown)));
    adapter.setStickers(manifest.getStickers());

    Sticker first = manifest.getStickers().isEmpty() ? null : manifest.getStickers().get(0);
    Sticker cover = OptionalUtil.or(manifest.getCover(), Optional.ofNullable(first)).orElse(null);

    if (cover != null) {
      Object  model = cover.getUri().isPresent() ? new DecryptableStreamUriLoader.DecryptableUri(cover.getUri().get())
                                                 : new StickerRemoteUri(cover.getPackId(), cover.getPackKey(), cover.getId());
      GlideApp.with(this).load(model)
                         .transition(DrawableTransitionOptions.withCrossFade())
                         .set(ApngOptions.ANIMATE, DeviceProperties.shouldAllowApngStickerAnimation(this))
                         .into(coverImage);
    } else {
      coverImage.setImageDrawable(null);
    }
  }

  private void presentButton(boolean installed) {
    if (installed) {
      removeButton.setVisibility(View.VISIBLE);
      removeButton.setOnClickListener(v -> {
        viewModel.onRemoveClicked();
        finish();
      });
      installButton.setVisibility(View.GONE);
      installButton.setOnClickListener(null);
    } else {
      installButton.setVisibility(View.VISIBLE);
      installButton.setOnClickListener(v -> {
        viewModel.onInstallClicked();
        finish();
      });
      removeButton.setVisibility(View.GONE);
      removeButton.setOnClickListener(null);
    }
  }

  private void presentShareButton(boolean installed, @NonNull String packId, @NonNull String packKey) {
    if (installed) {
      shareButton.setVisibility(View.VISIBLE);
      shareButtonImage.setVisibility(View.VISIBLE);
      shareButton.setOnClickListener(v -> {
        Intent composeIntent = new Intent(this, ShareActivity.class);
        composeIntent.putExtra(Intent.EXTRA_TEXT, StickerUrl.createShareLink(packId, packKey));
        startActivity(composeIntent);
        finish();
      });
    } else {
      shareButton.setVisibility(View.GONE);
      shareButtonImage.setVisibility(View.GONE);
      shareButton.setOnClickListener(null);
    }
  }

  private void presentError() {
    Toast.makeText(this, R.string.StickerPackPreviewActivity_failed_to_load_sticker_pack, Toast.LENGTH_SHORT).show();
    finish();
  }

  private void onScreenWidthChanged(int screenWidth) {
    if (layoutManager != null) {
      int availableWidth = screenWidth - (2 * getResources().getDimensionPixelOffset(R.dimen.sticker_preview_gutter_size));
      layoutManager.setSpanCount(availableWidth / getResources().getDimensionPixelOffset(R.dimen.sticker_preview_sticker_size));
    }
  }

  private int getScreenWidth() {
    Point size = new Point();
    getWindowManager().getDefaultDisplay().getSize(size);
    return size.x;
  }
}
