package ch.threema.app.ui;

import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.ImageView;

import com.google.android.material.card.MaterialCardView;
import com.google.android.material.progressindicator.CircularProgressIndicator;
import com.google.android.material.shape.ShapeAppearanceModel;

import org.slf4j.Logger;

import androidx.annotation.ColorInt;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import androidx.appcompat.widget.AppCompatImageView;

import ch.threema.app.R;
import ch.threema.app.utils.ConfigUtils;
import static ch.threema.base.utils.LoggingKt.getThreemaLogger;

public class ControllerView extends MaterialCardView {
    private static final Logger logger = getThreemaLogger("ControllerView");

    private CircularProgressIndicator progressBarIndeterminate, progressBarDeterminate;
    private AppCompatImageView iconImageView;
    private int status, progressMax = 100;

    private boolean hasBackgroundImage = false;
    private boolean isUsedForOutboxMessage = false;
    @DrawableRes
    private int lastIconRes = 0;

    public final static int STATUS_NONE = 0;
    public final static int STATUS_PROGRESSING = 1;
    public final static int STATUS_READY_TO_DOWNLOAD = 2;
    public final static int STATUS_READY_TO_PLAY = 3;
    public final static int STATUS_PLAYING = 4;
    public final static int STATUS_READY_TO_RETRY = 5;
    public final static int STATUS_PROGRESSING_NO_CANCEL = 6;
    public final static int STATUS_TRANSCODING = 8;

    public ControllerView(Context context) {
        super(context);
        init(context);
    }

    public ControllerView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public ControllerView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(@NonNull Context context) {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.conversation_list_item_controller_view, this);

        this.setCardBackgroundColor(getBackgroundColorStateList());
        this.setShapeAppearanceModel(ShapeAppearanceModel.builder(context, 0, R.style.ShapeAppearance_Material3_Corner_Medium).build());
        this.setStrokeWidth(0);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        progressBarIndeterminate = this.findViewById(R.id.progress);
        progressBarDeterminate = this.findViewById(R.id.progress_determinate);
        iconImageView = this.findViewById(R.id.icon);

        setBackgroundImage(null);
        initProgressBars();
    }

    private void initProgressBars() {
        progressBarIndeterminate.setIndicatorColor(getProgressTrackIndicatorColor());
        progressBarDeterminate.setIndicatorColor(getProgressTrackIndicatorColor());
    }

    private void reset() {
        if (getVisibility() != VISIBLE) {
            setVisibility(VISIBLE);
        }
        if (progressBarIndeterminate.getVisibility() == VISIBLE) {
            progressBarIndeterminate.setVisibility(INVISIBLE);
        }
        if (progressBarDeterminate.getVisibility() == VISIBLE) {
            progressBarDeterminate.setVisibility(INVISIBLE);
        }
        if (iconImageView.getVisibility() != VISIBLE) {
            iconImageView.setVisibility(VISIBLE);
        }
    }

    public void setNeutral() {
        logger.debug("setNeutral");
        reset();
        status = STATUS_NONE;
    }

    public void setHidden() {
        logger.debug("setHidden");
        setVisibility(INVISIBLE);
        status = STATUS_NONE;
    }

    @UiThread
    public void setPlay() {
        logger.debug("setPlay");
        if (status != STATUS_READY_TO_PLAY) {
            setIconResource(R.drawable.ic_play);
            setContentDescription(getContext().getString(R.string.play));
            status = STATUS_READY_TO_PLAY;
        }
    }

    @UiThread
    public void setPause() {
        logger.debug("setPause");
        setIconResource(R.drawable.ic_pause);
        setContentDescription(getContext().getString(R.string.pause));
        status = STATUS_PLAYING;
    }

    public void setTranscoding() {
        setHidden();
        status = STATUS_TRANSCODING;
    }

    public void setProgressing() {
        setProgressing(true);
    }

    @UiThread
    public void setProgressing(boolean cancelable) {
        logger.debug("setProgressing cancelable = {}", cancelable);
        if (progressBarIndeterminate.getVisibility() != VISIBLE) {
            reset();
            if (cancelable) {
                if (status != STATUS_PROGRESSING) {
                    setIconResource(R.drawable.ic_close);
                    status = STATUS_PROGRESSING;
                }
            } else {
                if (status != STATUS_PROGRESSING_NO_CANCEL) {
                    iconImageView.setVisibility(INVISIBLE);
                    status = STATUS_PROGRESSING_NO_CANCEL;
                }
            }
            progressBarIndeterminate.setVisibility(VISIBLE);
        } else {
            var newStatus = cancelable
                ? STATUS_PROGRESSING
                : STATUS_PROGRESSING_NO_CANCEL;
            if (status == newStatus && getVisibility() == VISIBLE) {
                // nothing has changed, no need to call requestLayout()
                return;
            }

            setVisibility(VISIBLE);
            status = newStatus;
        }
        requestLayout();
    }

    public void setProgressingDeterminate(int max) {
        logger.debug("setProgressingDeterminate max = {}", max);
        setBackgroundImage(null);
        setIconResource(R.drawable.ic_close);
        setContentDescription(getContext().getString(R.string.cancel));
        progressBarDeterminate.setMax(max);
        progressBarDeterminate.setProgress(0);
        progressBarDeterminate.setVisibility(VISIBLE);
        status = STATUS_PROGRESSING;
        progressMax = max;
    }

    public void setProgress(int progress) {
        logger.debug("setProgress progress = {}", progress);
        if (progressBarDeterminate.getVisibility() != VISIBLE) {
            setProgressingDeterminate(progressMax);
        }
        progressBarDeterminate.setProgress(progress);
    }

    public void setRetry() {
        logger.debug("setRetry");
        setIconResource(R.drawable.outline_refresh_24);
        setContentDescription(getContext().getString(R.string.retry));
        status = STATUS_READY_TO_RETRY;
    }

    public void setReadyToDownload() {
        logger.debug("setReadyToDownload");
        setIconResource(R.drawable.outline_file_download_24);
        setContentDescription(getContext().getString(R.string.download));
        status = STATUS_READY_TO_DOWNLOAD;
    }

    public void setIconResource(@DrawableRes int resource) {
        if (resource == lastIconRes) {
            return;
        }
        lastIconRes = resource;
        logger.debug("setImageResource");
        reset();
        hasBackgroundImage = false;
        iconImageView.setImageTintList(getIconColorStateList());
        iconImageView.setScaleType(ImageView.ScaleType.CENTER);
        iconImageView.setImageResource(resource);
    }

    public void setBackgroundImage(@Nullable Bitmap bitmap) {
        logger.debug("setBackgroundImage");
        hasBackgroundImage = bitmap != null;
        if (bitmap != null) {
            iconImageView.setImageTintList(null);
            iconImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
            iconImageView.setImageDrawable(new BitmapDrawable(getResources(), bitmap));
            lastIconRes = 0;
        }
    }

    public int getStatus() {
        return status;
    }

    public void setIsUsedForOutboxMessage(boolean isOutboxMessage) {
        if (this.isUsedForOutboxMessage != isOutboxMessage) {
            this.isUsedForOutboxMessage = isOutboxMessage;
            if (!hasBackgroundImage) {
                iconImageView.setImageTintList(getIconColorStateList());
            }
            initProgressBars();
        }
    }

    @NonNull
    private ColorStateList getBackgroundColorStateList() {
        return getContext().getColorStateList(R.color.controller_view_background_colorstatelist);
    }

    private @ColorInt int getProgressTrackIndicatorColor() {
        return ConfigUtils.getColorFromAttribute(getContext(), R.attr.colorOnSecondary);
    }

    @NonNull
    private ColorStateList getIconColorStateList() {
        return getContext().getColorStateList(R.color.controller_view_on_background_colorstatelist);
    }
}
