package chaoran.business.utils;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Environment;
import android.provider.Settings;
import android.provider.MediaStore;
import android.util.Base64;
import android.util.Log;
import android.view.Surface;
import android.view.View;
import android.view.WindowManager;
import android.webkit.JavascriptInterface;
import android.webkit.WebView;

import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;

import org.json.JSONObject;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Date;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Random;

import chaoran.business.BuildConfig;

public class LocalAddressUtil {

    public final static String SSO_KEY = "!~CROP@CRTECH@PDA~!";

    private Context context;

    private Activity activity;

    private View view;

    private int[] heights;

    private static final String TAG = "LocalAddressUtil";
    private static final int REQUEST_CODE_NATIVE_CAMERA = 31002;
    private static final int REQUEST_CODE_PERMISSION_CAMERA = 31001;
    private static final String DEFAULT_CAMERA_CALLBACK = "onNativeCameraResult";

    // Base64 settings for camera callback
    private static final int CAMERA_IMAGE_MAX_DIMENSION = 1280;
    private static final int CAMERA_IMAGE_JPEG_QUALITY = 80;
    private static final String CAMERA_DATA_URL_PREFIX = "data:image/jpeg;base64,";

    private Uri nativeCameraPhotoUri;
    private String pendingCameraCallback = null;

    public LocalAddressUtil(Context context, Activity activity, View view) {
        this.context = context;
        this.activity = activity;
        this.view = view;
        this.heights = StatusBarUtil.getStatusBarHeight(context);
    }

    /**
     * 直接调用原生相机（默认回调：window.onNativeCameraResult(base64OrDataUrl, error)）
     */
    @SuppressLint("JavascriptInterface")
    @JavascriptInterface
    public void openNativeCamera() {
        openNativeCamera(DEFAULT_CAMERA_CALLBACK);
    }

    /**
     * 直接调用原生相机（自定义回调函数名：window[callback](base64OrDataUrl, error)）
     * @param callback JS 回调函数名（不需要传 window. 前缀）
     */
    @SuppressLint("JavascriptInterface")
    @JavascriptInterface
    public void openNativeCamera(String callback) {
        this.pendingCameraCallback = (callback == null || callback.trim().isEmpty())
                ? DEFAULT_CAMERA_CALLBACK
                : callback.trim();

        if (!checkCameraPermission()) {
            ActivityCompat.requestPermissions(activity,
                    new String[]{android.Manifest.permission.CAMERA},
                    REQUEST_CODE_PERMISSION_CAMERA);
            return;
        }

        Intent cameraIntent = createNativeCameraIntent();
        if (cameraIntent == null) {
            dispatchCameraResultToJs(null, "create_intent_failed");
            return;
        }

        try {
            activity.startActivityForResult(cameraIntent, REQUEST_CODE_NATIVE_CAMERA);
        } catch (Exception e) {
            Log.e(TAG, "启动相机失败", e);
            dispatchCameraResultToJs(null, "start_failed");
        }
    }

    /**
     * 由宿主 Activity 转发调用
     */
    public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode != REQUEST_CODE_NATIVE_CAMERA) {
            return false;
        }
        if (resultCode == Activity.RESULT_OK) {
            String dataUrl = buildCameraPhotoDataUrl(nativeCameraPhotoUri);
            if (dataUrl == null || dataUrl.trim().isEmpty()) {
                dispatchCameraResultToJs(null, "encode_failed");
            } else {
                dispatchCameraResultToJs(dataUrl, null);
            }
        } else {
            dispatchCameraResultToJs(null, "cancelled");
        }
        nativeCameraPhotoUri = null;
        return true;
    }

    /**
     * 由宿主 Activity 转发调用
     */
    public boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        if (requestCode != REQUEST_CODE_PERMISSION_CAMERA) {
            return false;
        }
        boolean granted = grantResults != null && grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED;
        if (granted) {
            openNativeCamera(pendingCameraCallback);
        } else {
            dispatchCameraResultToJs(null, "permission_denied");
        }
        return true;
    }

    private boolean checkCameraPermission() {
        return ContextCompat.checkSelfPermission(activity, android.Manifest.permission.CAMERA)
                == PackageManager.PERMISSION_GRANTED;
    }

    private Intent createNativeCameraIntent() {
        Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        if (cameraIntent.resolveActivity(activity.getPackageManager()) == null) {
            return null;
        }
        File photoFile = createImageFile();
        if (photoFile == null) {
            return null;
        }
        nativeCameraPhotoUri = FileProvider.getUriForFile(
                activity,
                activity.getPackageName() + ".fileprovider",
                photoFile
        );
        cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, nativeCameraPhotoUri);
        cameraIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        cameraIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        return cameraIntent;
    }

    private File createImageFile() {
        try {
            String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
            String imageFileName = "JPEG_" + timeStamp + "_";
            File storageDir = activity.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
            if (storageDir != null && !storageDir.exists()) {
                //noinspection ResultOfMethodCallIgnored
                storageDir.mkdirs();
            }
            return File.createTempFile(imageFileName, ".jpg", storageDir);
        } catch (IOException e) {
            Log.e(TAG, "创建图片文件失败", e);
            return null;
        }
    }

    /**
     * 将拍照结果转为 dataUrl（base64）
     */
    private String buildCameraPhotoDataUrl(Uri uri) {
        if (uri == null) {
            return null;
        }
        InputStream inputStream = null;
        try {
            inputStream = context.getContentResolver().openInputStream(uri);
            if (inputStream == null) {
                return null;
            }

            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(inputStream, null, options);
            int srcW = options.outWidth;
            int srcH = options.outHeight;

            safeClose(inputStream);
            inputStream = context.getContentResolver().openInputStream(uri);
            if (inputStream == null) {
                return null;
            }

            options.inSampleSize = calculateInSampleSize(srcW, srcH, CAMERA_IMAGE_MAX_DIMENSION);
            options.inJustDecodeBounds = false;

            Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, options);
            if (bitmap == null) {
                return null;
            }

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            bitmap.compress(Bitmap.CompressFormat.JPEG, CAMERA_IMAGE_JPEG_QUALITY, baos);
            byte[] bytes = baos.toByteArray();

            String base64 = Base64.encodeToString(bytes, Base64.NO_WRAP);
            return CAMERA_DATA_URL_PREFIX + base64;
        } catch (Exception e) {
            Log.e(TAG, "图片转base64失败", e);
            return null;
        } finally {
            safeClose(inputStream);
        }
    }

    private int calculateInSampleSize(int srcW, int srcH, int maxDim) {
        if (srcW <= 0 || srcH <= 0) {
            return 1;
        }
        int maxSrc = Math.max(srcW, srcH);
        if (maxSrc <= maxDim) {
            return 1;
        }
        int inSampleSize = 1;
        while (maxSrc / inSampleSize > maxDim) {
            inSampleSize *= 2;
        }
        return Math.max(1, inSampleSize);
    }

    private void safeClose(InputStream is) {
        try {
            if (is != null) {
                is.close();
            }
        } catch (Exception ignored) {
        }
    }

    private void dispatchCameraResultToJs(String dataUrl, String error) {
        if (!(view instanceof WebView)) {
            return;
        }
        WebView webView = (WebView) view;
        String cb = (pendingCameraCallback == null || pendingCameraCallback.trim().isEmpty())
                ? DEFAULT_CAMERA_CALLBACK
                : pendingCameraCallback.trim();

        String js = "try{" +
                "var cb=window[" + JSONObject.quote(cb) + "];" +
                "if(typeof cb==='function'){cb(" + JSONObject.quote(dataUrl) + "," + JSONObject.quote(error) + ");}" +
                "}catch(e){}";

        webView.post(() -> {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                webView.evaluateJavascript(js, null);
            } else {
                webView.loadUrl("javascript:" + js);
            }
        });
    }

    @SuppressLint("JavascriptInterface")
    @JavascriptInterface
    public String getIpAddress() {
        try {
            for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
                NetworkInterface intf = en.nextElement();
                // if(!intf.getDisplayName().equals("eth0")) continue;
                for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
                    InetAddress inetAddress = enumIpAddr.nextElement();
                    if (!inetAddress.isLoopbackAddress()  && inetAddress instanceof Inet4Address) {
                        return inetAddress.getHostAddress();
                    }
                }
            }
        } catch (SocketException ex) {
            Log.e("address: local", ex.toString());
        }
        return null;
    }

    @SuppressLint("JavascriptInterface")
    @JavascriptInterface
    public String getMacAddress(){//可以兼容安卓7以下
        SharedPreferences spf = context.getSharedPreferences("chaoran_mac", Context.MODE_PRIVATE);
        String saveMac  = spf.getString("chaoran_mac", "");
        if (!"".equalsIgnoreCase(saveMac)) {
            return saveMac;
        }
        SharedPreferences.Editor editor = spf.edit();
        String androidMac = getAndroidMac();
        editor.putString("chaoran_mac", androidMac);
        editor.apply();
        return androidMac;
    }

    /**
     * 获取安卓的mac
     * @return
     */
    private String getAndroidMac() {
        if (Build.VERSION.SDK_INT >= 34) { // Android 14 is code-named Tiramisu
            try {
                return Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
            }catch (Exception e) {
                e.printStackTrace();
                return generateRandomMacAddress();
            }
        }
        String macAddress = null;
        StringBuffer buf = new StringBuffer();
        NetworkInterface networkInterface = null;
        try {
            networkInterface = NetworkInterface.getByName("eth1");
            if (networkInterface == null) {
                networkInterface = NetworkInterface.getByName("wlan0");
            }
            if (networkInterface == null) {
                return generateRandomMacAddress();
            }
            byte[] addr = networkInterface.getHardwareAddress();
            for (byte b : addr) {
                buf.append(String.format("%02X:", b));
            }
            if (buf.length() > 0) {
                buf.deleteCharAt(buf.length() - 1);
            }
            macAddress = buf.toString();
        } catch (Exception e) {
            e.printStackTrace();
            macAddress = generateRandomMacAddress();
        }
        if (macAddress.length() < 4) {
            macAddress = generateRandomMacAddress();
        }
        return macAddress;
    }

    private static String generateRandomMacAddress() {
        Random rand = new Random();
        byte[] macBytes = new byte[6];
        rand.nextBytes(macBytes);
        macBytes[0] = (byte) (macBytes[0] & 0xfe | 0x02);
        StringBuilder macAddress = new StringBuilder();
        for (int i = 0; i < macBytes.length; i++) {
            macAddress.append(String.format("%02X%s", macBytes[i], (i < macBytes.length - 1) ? ":" : ""));
        }
        return macAddress.toString();
    }

    @SuppressLint("JavascriptInterface")
    @JavascriptInterface
    public String getInfo(int type){
        String info;
        switch (type) {
            case 1: info =  Build.BRAND;break;//品牌
            case 2: info = Build.MODEL;break;//型号
            case 3: info = Build.MANUFACTURER;break;//厂商
            case 4: info = Build.DEVICE;break;//设备名
            case 5: info = Build.ID;break;//设备硬件id
//            case 6: info = Build.SERIAL;break;//序列号，可能获取不到
            default: info = "";break;
        }
        return info;
    }

    @SuppressLint("JavascriptInterface")
    @JavascriptInterface
    public String getHeight(int type) {
        String info = "";
        switch (type) {
            case 1 : info = String.valueOf(this.heights[0]); break;
            case 2 : info = String.valueOf(this.heights[1]); break;
        }
        return info;
    }

    public void test(){
        Log.e("test", "MANUFACTURER=" + Build.MANUFACTURER);
        Log.e("test", "BRAND=" + Build.BRAND);
        Log.e("test", "MODEL=" + Build.MODEL);
        Log.e("test", "VERSION.RELEASE=" + Build.VERSION.RELEASE);
        Log.e("test", "VERSION.SDK_INT=" + Build.VERSION.SDK_INT);
        Log.e("test", "DEVICE=" + Build.DEVICE);
        Log.e("test", "HOST=" + Build.HOST);
        Log.e("test", "ID=" + Build.ID);
        Log.e("test", "TIME=" + Build.TIME);
        Log.e("test", "TYPE=" + Build.TYPE);
        Log.e("test", "PRODUCT=" + Build.PRODUCT);
        Log.e("test", "BOARD=" + Build.BOARD);
        Log.e("test", "DISPLAY=" + Build.DISPLAY);
        Log.e("test", "FINGERPRINT=" + Build.FINGERPRINT);
        Log.e("test", "HARDWARE=" + Build.HARDWARE);
        Log.e("test", "BOOTLOADER=" + Build.BOOTLOADER);
        Log.e("test", "TAGS=" + Build.TAGS);
        Log.e("test", "UNKNOWN=" + Build.UNKNOWN);
        Log.e("test", "USER=" + Build.USER);
    }

    @SuppressLint("JavascriptInterface")
    @JavascriptInterface
    public void rotateScreen() {
        int angle = ((WindowManager)activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();

        switch (angle) {
            case Surface.ROTATION_0:
                activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
                break;
            case Surface.ROTATION_90:
                activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
                break;
            case Surface.ROTATION_180:
                activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                break;
            case Surface.ROTATION_270:
                activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                break;
            default:
                break;
        }
    }

    @SuppressLint("JavascriptInterface")
    @JavascriptInterface
    public String registerMac(String applyMac) {
        try {
            String mac = this.getMacAddress();
            String md5Hash = MD5.md5(mac + SSO_KEY);
            if ("Crtech!register@PDA#APK".equals(applyMac) || (md5Hash != null && md5Hash.equals(applyMac))) {
                // 将允许注册适配的mac写入文件中
                SharedPreferences.Editor editor = context.getSharedPreferences("CrtechPdaConfig", Context.MODE_PRIVATE).edit();
                editor.putString("checkMac", "success");
                if ("Crtech!register@PDA#APK".equals(applyMac)) {
                    editor.putString("checkMacTime", String.valueOf(System.currentTimeMillis()));
                    editor.putString("checkMacType", "1");
                }else {
                    editor.putString("checkMacType", "0");
                }
                editor.commit();
                return "success";
            }
        }catch (Exception ignored) {

        }
        return "error";
    }

    @SuppressLint("JavascriptInterface")
    @JavascriptInterface
    public String checkMacRegister() {
        SharedPreferences sharedPreferences = context.getSharedPreferences("CrtechPdaConfig", Context.MODE_PRIVATE);
        String checkMac = sharedPreferences.getString("checkMac", "error");
        if (!"success".equals(checkMac)) {
            return "error";
        }
        if ("1".equals(sharedPreferences.getString("checkMacType", "0"))) {
            // 判断是否是强行注册的，强行注册的只允许使用一个小时；一但判断到，就取消注册
            Long aLong = Long.valueOf(sharedPreferences.getString("checkMacTime", String.valueOf(System.currentTimeMillis())));
            if ((aLong + 1 * 60 * 60 * 1000) < System.currentTimeMillis()) {
                SharedPreferences.Editor edit = sharedPreferences.edit();
                edit.putString("checkMac", "error");
                edit.commit();
                return "error";
            }
        }
        return "success";
    }

    @SuppressLint("JavascriptInterface")
    @JavascriptInterface
    public String getApkVersion() {
        return BuildConfig.VERSION_NAME;
    }

    /**
     * 暴露PDA的厂家和型号
     * @return String 格式：厂家：型号
     */
    @SuppressLint("JavascriptInterface")
    @JavascriptInterface
    public String getPdaInfo() {
        return Build.MANUFACTURER + "：" + Build.MODEL.toLowerCase();
    }
}
