package com.tencent.qian.webview.client;

import android.content.Context;
import android.graphics.Bitmap;
import android.net.http.SslError;
import android.os.Build;
import android.webkit.RenderProcessGoneDetail;
import android.webkit.SslErrorHandler;
import android.webkit.WebResourceError;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.core.util.Supplier;

import com.tencent.qian.webview.model.SdkEvent;
import com.tencent.qian.webview.model.SignCallback;
import com.tencent.qian.webview.scheme.ExternalSchemeHandler;
import com.tencent.qian.webview.scheme.SchemeInterceptor;

/**
 * SDK 内置 WebViewClient。
 */
public class QianWebViewClient extends WebViewClient {

    private final SchemeInterceptor schemeInterceptor;
    private final ExternalSchemeHandler externalSchemeHandler;
    private final Supplier<SignCallback> callbackProvider;
    private final Supplier<Context> contextProvider;

    public QianWebViewClient(
            @NonNull SchemeInterceptor schemeInterceptor,
            @NonNull ExternalSchemeHandler externalSchemeHandler,
            @NonNull Supplier<SignCallback> callbackProvider,
            @NonNull Supplier<Context> contextProvider
    ) {
        this.schemeInterceptor = schemeInterceptor;
        this.externalSchemeHandler = externalSchemeHandler;
        this.callbackProvider = callbackProvider;
        this.contextProvider = contextProvider;
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    @Override
    public boolean shouldOverrideUrlLoading(@NonNull WebView view, @NonNull WebResourceRequest request) {
        return overrideUrl(request.getUrl() != null ? request.getUrl().toString() : null);
    }

    @SuppressWarnings("deprecation")
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        return overrideUrl(url);
    }

    private boolean overrideUrl(@Nullable String url) {
        if (url == null || url.isEmpty()) return false;

        if (schemeInterceptor.handle(url)) return true;

        String lower = url.toLowerCase();
        if (lower.startsWith("http://") || lower.startsWith("https://")) return false;

        Context ctx = contextProvider.get();
        if (ctx == null) return false;
        return externalSchemeHandler.tryStartActivity(ctx, url);
    }

    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        SignCallback cb = callbackProvider.get();
        if (cb != null) cb.onEvent(new SdkEvent.PageStarted(url != null ? url : ""));
    }

    @Override
    public void onPageFinished(WebView view, String url) {
        SignCallback cb = callbackProvider.get();
        if (cb != null) cb.onEvent(new SdkEvent.PageFinished(url != null ? url : ""));
    }

    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    public void onReceivedError(@NonNull WebView view, @NonNull WebResourceRequest request, @NonNull WebResourceError error) {
        if (!request.isForMainFrame()) return;
        SignCallback cb = callbackProvider.get();
        if (cb != null) cb.onEvent(new SdkEvent.LoadError(
                request.getUrl() != null ? request.getUrl().toString() : "",
                error.getErrorCode(),
                error.getDescription() != null ? error.getDescription().toString() : ""));
    }

    @SuppressWarnings("deprecation")
    @Override
    public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
        SignCallback cb = callbackProvider.get();
        if (cb != null) cb.onEvent(new SdkEvent.LoadError(
                failingUrl != null ? failingUrl : "", errorCode, description != null ? description : ""));
    }

    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    public void onReceivedHttpError(@NonNull WebView view, @NonNull WebResourceRequest request, @NonNull WebResourceResponse errorResponse) {
        if (!request.isForMainFrame()) return;
        SignCallback cb = callbackProvider.get();
        if (cb != null) cb.onEvent(new SdkEvent.HttpError(
                request.getUrl() != null ? request.getUrl().toString() : "",
                errorResponse.getStatusCode(),
                errorResponse.getReasonPhrase() != null ? errorResponse.getReasonPhrase() : ""));
    }

    @Override
    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
        if (handler != null) handler.cancel();
        SignCallback cb = callbackProvider.get();
        if (cb != null) cb.onEvent(new SdkEvent.SslError(
                error != null && error.getUrl() != null ? error.getUrl() : "",
                error != null ? error.getPrimaryError() : -1));
    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    public boolean onRenderProcessGone(WebView view, RenderProcessGoneDetail detail) {
        boolean didCrash = detail != null && detail.didCrash();
        SignCallback cb = callbackProvider.get();
        if (cb != null) cb.onEvent(new SdkEvent.RenderProcessGone(didCrash,
                view != null && view.getUrl() != null ? view.getUrl() : ""));
        return true;
    }
}
