package com.datarecovery.master.dialog;

import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;

import androidx.annotation.CallSuper;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.ViewDataBinding;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleEventObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
import androidx.viewbinding.ViewBinding;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;

public class BaseDialog<T extends ViewBinding> extends Dialog implements Comparable<BaseDialog<T>>,
        LifecycleOwner, LifecycleEventObserver {

    protected T binding;

    private Handler handler;

    private int gravity;

    private int margin;

    private LifecycleRegistry lifecycleRegistry;

    private Lifecycle ownerActivityLifecycle;

    @Retention(RetentionPolicy.SOURCE)
    @IntDef({
            HIGH_PRIORITY,
            DEFAULT_PRIORITY,
            LOW_PRIORITY
    })
    @interface Priority {

    }

    static final int HIGH_PRIORITY = 100;

    static final int DEFAULT_PRIORITY = 50;
    static final int LOW_PRIORITY = 0;
    private OnDismissListener onDismissListener;

    private OnShowListener onShowListener;
    private boolean widthFullScreen;
    private boolean heightFullScreen;

    public BaseDialog(@NonNull Context context) {
        super(context);
        init(context);
    }

    public BaseDialog(@NonNull Context context, int themeResId) {
        super(context, themeResId);
        init(context);
    }

    protected BaseDialog(@NonNull Context context, boolean cancelable, @Nullable OnCancelListener cancelListener) {
        super(context, cancelable, cancelListener);
        init(context);
    }

    private void init(Context context) {
        handler = new Handler(Looper.getMainLooper());

        lifecycleRegistry = new LifecycleRegistry(this);

        initBinding();

        initDialogParams();

        initDialogOwner(context);

        initListener();

        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
    }

    private void initDialogOwner(Context context) {
        Activity activity = context instanceof Activity ? ((Activity) context) : null;
        if (activity != null) {
            setOwnerActivity(activity);
        }
        AppCompatActivity appCompatActivity = activity instanceof AppCompatActivity ? ((AppCompatActivity) activity) : null;
        if (appCompatActivity != null) {
            ownerActivityLifecycle = appCompatActivity.getLifecycle();
            ownerActivityLifecycle.addObserver(this);
        }
    }

    private void initListener() {
        super.setOnDismissListener(dialog -> {
            if (lifecycleRegistry.getCurrentState() != Lifecycle.State.DESTROYED) {
                lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
            }
            if (onDismissListener != null) {
                onDismissListener.onDismiss(dialog);
            }
            onDismiss();
            if (useQueue()) {
                DialogQueue.nextDialog();
            }
        });
        super.setOnShowListener(dialog -> {
            lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
            if (onShowListener != null) {
                onShowListener.onShow(dialog);
            }
            onShow();
        });
    }

    private void initDialogParams() {
        Class<? extends BaseDialog> aClass = this.getClass();
        FullScreen annotation = aClass.getAnnotation(FullScreen.class);
        if (annotation != null) {
            widthFullScreen = annotation.width();
            heightFullScreen = annotation.height();
            gravity = annotation.gravity();
        }
    }

    private void initBinding() {
        try {
            ParameterizedType type = getClass().getGenericSuperclass() instanceof ParameterizedType
                    ? ((ParameterizedType) getClass().getGenericSuperclass()) : null;
            if (type == null) {
                return;
            }
            Class<? extends ViewBinding> bindingClass = (Class<? extends ViewBinding>) type.getActualTypeArguments()[0];
            try {
                Method inflate = bindingClass.getMethod("inflate", LayoutInflater.class);
                binding = (T) inflate.invoke(null, getLayoutInflater());
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
            ViewDataBinding viewDataBinding = binding instanceof ViewDataBinding ? ((ViewDataBinding) binding) : null;
            if (viewDataBinding != null) {
                viewDataBinding.setLifecycleOwner(this);
            }
            if (binding != null) {
                setContentView(binding.getRoot());
            }
        } catch (Exception e) {
        }
    }

    public void setMargin(int margin) {
        this.margin = margin;
    }

    protected void onShow() {
    }

    protected void onDismiss() {
    }

    @Override
    public void setOnDismissListener(@Nullable OnDismissListener listener) {
        onDismissListener = listener;
    }

    @Override
    public void setOnShowListener(@Nullable OnShowListener listener) {
        onShowListener = listener;
    }

    @Override
    @CallSuper
    public void show() {
        if (useQueue()) {
            DialogQueue.requestShow(this);
        } else {
            showInternal();
        }
    }

    void showInternal() {
        if (couldShow()) {
            super.show();
            Window window = getWindow();
            WindowManager.LayoutParams attributes = window.getAttributes();
            attributes.height = heightFullScreen ? WindowManager.LayoutParams.MATCH_PARENT : WindowManager.LayoutParams.WRAP_CONTENT;
            attributes.width = widthFullScreen ? WindowManager.LayoutParams.MATCH_PARENT : WindowManager.LayoutParams.WRAP_CONTENT;
            attributes.gravity = gravity;
            //todo 暂时只处理TOP的margin,bottom待添加
            if (gravity == Gravity.TOP) {
                attributes.y = margin;
            }

            window.setAttributes(attributes);
        } else {
            if (useQueue()) {
                DialogQueue.nextDialog();
            }
        }
    }

    private boolean couldShow() {
        if (isShowing()) {
            return false;
        }
        if (getOwnerActivity() != null) {
            return !getOwnerActivity().isDestroyed() && !getOwnerActivity().isFinishing();
        }
        Context context = getContext();
        if (context instanceof Activity) {
            Activity activity = (Activity) context;
            return !activity.isDestroyed() && !activity.isFinishing();
        }
        return true;
    }

    @Override
    @CallSuper
    public void dismiss() {
        handler.post(() -> {
            if (isShowing() && isDecorViewAttach()) {
                super.dismiss();
            }
        });
    }

    private boolean isDecorViewAttach() {
        Window window = getWindow();
        if (window == null) {
            return false;
        }
        View decorView = window.getDecorView();
        if (decorView == null) {
            return false;
        }
        return decorView.isAttachedToWindow();
    }

    @Override
    public int compareTo(BaseDialog other) {
        if (other == null) {
            return 1;
        }
        if (getPriority() == other.getPriority()) {
            return 0;
        }
        return getPriority() < other.getPriority() ? 1 : -1;
    }

    @Priority
    protected int getPriority() {
        return DEFAULT_PRIORITY;
    }

    protected boolean useQueue() {
        return true;
    }

    @NonNull
    @Override
    public Lifecycle getLifecycle() {
        return lifecycleRegistry;
    }

    @Override
    public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
        if (event == Lifecycle.Event.ON_DESTROY) {
            if (ownerActivityLifecycle != null) {
                ownerActivityLifecycle.removeObserver(this);
            }
            dismiss();
            lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
            return;
        }
        if (!isShowing()) {
            return;
        }
        if (event == Lifecycle.Event.ON_RESUME) {
            lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
        } else if (event == Lifecycle.Event.ON_PAUSE) {
            lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
        } else if (event == Lifecycle.Event.ON_START) {
            lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
        } else if (event == Lifecycle.Event.ON_STOP) {
            lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
        }
    }

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface FullScreen {
        boolean width() default true;

        boolean height() default true;

        int gravity() default Gravity.CENTER;
    }

}