package com.github.bkhezry.weather.utils;

import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.ForegroundColorSpan;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.ColorInt;
import androidx.annotation.DrawableRes;
import androidx.annotation.IntDef;
import androidx.annotation.IntRange;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;

import com.google.android.material.snackbar.Snackbar;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;

public final class SnackbarUtil {

  public static final int LENGTH_INDEFINITE = -2;
  public static final int LENGTH_SHORT = -1;
  public static final int LENGTH_LONG = 0;
  private static final int COLOR_DEFAULT = 0xFEFFFFFF;
  private static final int COLOR_SUCCESS = 0xFF2BB600;
  private static final int COLOR_WARNING = 0xFFFFC100;
  private static final int COLOR_ERROR = 0xFFFF0000;
  private static final int COLOR_MESSAGE = 0xFFFFFFFF;
  private static WeakReference<Snackbar> sReference;
  private View view;
  private CharSequence message;
  private int messageColor;
  private int bgColor;
  private int bgResource;
  private int duration;
  private CharSequence actionText;
  private int actionTextColor;
  private View.OnClickListener actionListener;
  private int bottomMargin;

  private SnackbarUtil(final View parent) {
    setDefault();
    this.view = parent;
  }

  /**
   * Set the view to find a parent from.
   *
   * @param view The view to find a parent from.
   * @return the single {@link SnackbarUtil} instance
   */
  public static SnackbarUtil with(@NonNull final View view) {
    return new SnackbarUtil(view);
  }

  /**
   * Dismiss the snackbar.
   */
  public static void dismiss() {
    if (sReference != null && sReference.get() != null) {
      sReference.get().dismiss();
      sReference = null;
    }
  }

  /**
   * Return the view of snackbar.
   *
   * @return the view of snackbar
   */
  public static View getView() {
    Snackbar snackbar = sReference.get();
    if (snackbar == null) return null;
    return snackbar.getView();
  }

  /**
   * Add view to the snackbar.
   * <p>Call it after {@link #show()}</p>
   *
   * @param layoutId The id of layout.
   * @param params   The params.
   */
  public static void addView(@LayoutRes final int layoutId,
                             @NonNull final ViewGroup.LayoutParams params) {
    final View view = getView();
    if (view != null) {
      view.setPadding(0, 0, 0, 0);
      Snackbar.SnackbarLayout layout = (Snackbar.SnackbarLayout) view;
      View child = LayoutInflater.from(view.getContext()).inflate(layoutId, null);
      layout.addView(child, -1, params);
    }
  }

  /**
   * Add view to the snackbar.
   * <p>Call it after {@link #show()}</p>
   *
   * @param child  The child view.
   * @param params The params.
   */
  public static void addView(@NonNull final View child,
                             @NonNull final ViewGroup.LayoutParams params) {
    final View view = getView();
    if (view != null) {
      view.setPadding(0, 0, 0, 0);
      Snackbar.SnackbarLayout layout = (Snackbar.SnackbarLayout) view;
      layout.addView(child, params);
    }
  }

  private void setDefault() {
    message = "";
    messageColor = COLOR_DEFAULT;
    bgColor = COLOR_DEFAULT;
    bgResource = -1;
    duration = LENGTH_SHORT;
    actionText = "";
    actionTextColor = COLOR_DEFAULT;
    bottomMargin = 0;
  }

  /**
   * Set the message.
   *
   * @param msg The message.
   * @return the single {@link SnackbarUtil} instance
   */
  public SnackbarUtil setMessage(@NonNull final CharSequence msg) {
    this.message = msg;
    return this;
  }

  /**
   * Set the color of message.
   *
   * @param color The color of message.
   * @return the single {@link SnackbarUtil} instance
   */
  public SnackbarUtil setMessageColor(@ColorInt final int color) {
    this.messageColor = color;
    return this;
  }

  /**
   * Set the color of background.
   *
   * @param color The color of background.
   * @return the single {@link SnackbarUtil} instance
   */
  public SnackbarUtil setBgColor(@ColorInt final int color) {
    this.bgColor = color;
    return this;
  }

  /**
   * Set the resource of background.
   *
   * @param bgResource The resource of background.
   * @return the single {@link SnackbarUtil} instance
   */
  public SnackbarUtil setBgResource(@DrawableRes final int bgResource) {
    this.bgResource = bgResource;
    return this;
  }

  /**
   * Set the duration.
   *
   * @param duration The duration.
   *                 <ul>
   *                 <li>{@link Duration#LENGTH_INDEFINITE}</li>
   *                 <li>{@link Duration#LENGTH_SHORT     }</li>
   *                 <li>{@link Duration#LENGTH_LONG      }</li>
   *                 </ul>
   * @return the single {@link SnackbarUtil} instance
   */
  public SnackbarUtil setDuration(@Duration final int duration) {
    this.duration = duration;
    return this;
  }

  /**
   * Set the action.
   *
   * @param text     The text.
   * @param listener The click listener.
   * @return the single {@link SnackbarUtil} instance
   */
  public SnackbarUtil setAction(@NonNull final CharSequence text,
                                @NonNull final View.OnClickListener listener) {
    return setAction(text, COLOR_DEFAULT, listener);
  }

  /**
   * Set the action.
   *
   * @param text     The text.
   * @param color    The color of text.
   * @param listener The click listener.
   * @return the single {@link SnackbarUtil} instance
   */

  public SnackbarUtil setAction(@NonNull final CharSequence text,
                                @ColorInt final int color,
                                @NonNull final View.OnClickListener listener) {
    this.actionText = text;
    this.actionTextColor = color;
    this.actionListener = listener;
    return this;
  }

  /**
   * Set the bottom margin.
   *
   * @param bottomMargin The size of bottom margin, in pixel.
   */
  public SnackbarUtil setBottomMargin(@IntRange(from = 1) final int bottomMargin) {
    this.bottomMargin = bottomMargin;
    return this;
  }

  /**
   * Show the snackbar.
   */
  public Snackbar show() {
    final View view = this.view;
    if (view == null) return null;
    if (messageColor != COLOR_DEFAULT) {
      SpannableString spannableString = new SpannableString(message);
      ForegroundColorSpan colorSpan = new ForegroundColorSpan(messageColor);
      spannableString.setSpan(
          colorSpan, 0, spannableString.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
      );
      sReference = new WeakReference<>(Snackbar.make(view, spannableString, duration));
    } else {
      sReference = new WeakReference<>(Snackbar.make(view, message, duration));
    }
    final Snackbar snackbar = sReference.get();
    final View snackbarView = snackbar.getView();
    if (bgResource != -1) {
      snackbarView.setBackgroundResource(bgResource);
    } else if (bgColor != COLOR_DEFAULT) {
      snackbarView.setBackgroundColor(bgColor);
    }
    if (bottomMargin != 0) {
      ViewGroup.MarginLayoutParams params =
          (ViewGroup.MarginLayoutParams) snackbarView.getLayoutParams();
      params.bottomMargin = bottomMargin;
    }
    if (actionText.length() > 0 && actionListener != null) {
      if (actionTextColor != COLOR_DEFAULT) {
        snackbar.setActionTextColor(actionTextColor);
      }
      snackbar.setAction(actionText, actionListener);
    }
    snackbar.show();
    return snackbar;
  }

  /**
   * Show the snackbar with success style.
   */
  public void showSuccess() {
    bgColor = COLOR_SUCCESS;
    messageColor = COLOR_MESSAGE;
    actionTextColor = COLOR_MESSAGE;
    show();
  }

  /**
   * Show the snackbar with warning style.
   */
  public void showWarning() {
    bgColor = COLOR_WARNING;
    messageColor = COLOR_MESSAGE;
    actionTextColor = COLOR_MESSAGE;
    show();
  }

  /**
   * Show the snackbar with error style.
   */
  public void showError() {
    bgColor = COLOR_ERROR;
    messageColor = COLOR_MESSAGE;
    actionTextColor = COLOR_MESSAGE;
    show();
  }

  @IntDef({LENGTH_INDEFINITE, LENGTH_SHORT, LENGTH_LONG})
  @Retention(RetentionPolicy.SOURCE)
  public @interface Duration {
  }
}