package com.xypower.mpapp;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.UriMatcher;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;

import com.xypower.common.FilesUtils;
import com.xypower.common.JSONUtils;
import com.xypower.common.MicroPhotoContext;

import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;

public class BridgeProvider extends ContentProvider {

    private final static String TAG = "MPLOG";
    private final static String AUTHORITY = "com.xypower.mpapp.provider";
    private final static String PATH_QUERY_SEC_VERSION = "/querySecVersion";
    private final static String PATH_QUERY_BATTERY_VOLTAGE = "/queryBatVol";
    private final static String PATH_IMP_PRI_KEY = "/importPriKey";
    private final static String PATH_IMP_PUB_KEY = "/importPubKey";
    private final static String PATH_GEN_KEYS = "/genKeys";
    private final static String PATH_GEN_CERT_REQ = "/genCertReq";

    private final static String PATH_TAKE_PHOTO = "/takePhoto";
    private final static String PATH_TAKE_VIDEO = "/takeVideo";

    private final static String PATH_HDRPLUS = "/hdrplus";

    private final static String PATH_RECOG_PIC = "/recogPic";

    public BridgeProvider() {
        Log.i(TAG, "BridgeProvider");
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        // Implement this to handle requests to delete one or more rows.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public String getType(Uri uri) {
        // TODO: Implement this to handle requests for the MIME type of the data
        // at the given URI.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {


        return null;
    }

    @Override
    public boolean onCreate() {
        // TODO: Implement this to initialize your content provider on startup.
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) {
        UriMatcher  matcher = new UriMatcher(UriMatcher.NO_MATCH);

        Log.i(TAG, uri.toString());
        matcher.addURI(AUTHORITY, PATH_QUERY_SEC_VERSION, 1);
        matcher.addURI(AUTHORITY, PATH_QUERY_BATTERY_VOLTAGE, 2);
        matcher.addURI(AUTHORITY, PATH_RECOG_PIC, 3);

        Cursor cursor = null;
        int matched = matcher.match(uri);
        switch (matched) {
            case 1:
                cursor = querySecVersion();
                break;
            case 2:
                cursor = queryBattaryVoltage();
                break;
            case 3:
                cursor = recoganizePicture(uri, selection, selectionArgs);
                break;
            default:
                break;
        }

        return cursor;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
                      String[] selectionArgs) {
        UriMatcher  matcher = new UriMatcher(UriMatcher.NO_MATCH);

        matcher.addURI(AUTHORITY, PATH_IMP_PRI_KEY, 1);
        matcher.addURI(AUTHORITY, PATH_IMP_PUB_KEY, 2);
        matcher.addURI(AUTHORITY, PATH_GEN_KEYS, 3);
        matcher.addURI(AUTHORITY, PATH_GEN_CERT_REQ, 4);
        matcher.addURI(AUTHORITY, PATH_TAKE_PHOTO, 5);
        matcher.addURI(AUTHORITY, PATH_TAKE_VIDEO, 6);
        matcher.addURI(AUTHORITY, PATH_HDRPLUS, 7);

        int res = 0;
        int matched = matcher.match(uri);
        switch (matched) {
            case 1:
                res = importPrivateKey(uri, values);
                break;
            case 2:
                res = importPublicKey(uri, values);
                break;
            case 3:
                res = genKeys(uri, values);
                break;
            case 4:
                res = genCertReq(uri, values);
                break;
            case 5:
                res = takePhoto(uri, values);
                break;
            case 6:
                res = takeVideo(uri, values);
                break;
            case 7:
                res = hdrPlus(uri, values);
                break;
            default:
                break;
        }

        return res;
    }

    private Cursor querySecVersion() {
        String version = MicroPhotoService.querySecVersion();
        String[] columns = { "version" };
        MatrixCursor matrixCursor = new MatrixCursor(columns, 1);
        matrixCursor.addRow(new Object[] { version });
        return matrixCursor;
    }

    private Cursor queryBattaryVoltage() {
        // #define CMD_GET_CHARGING_BUS_VOLTAGE_STATE      112
        // #define CMD_GET_BAT_VOL_STATE                   115
        // #define CMD_GET_BAT_BUS_VOLTAGE_STATE           117
        int bv = MicroPhotoService.getGpioInt(117);
        int bcv = MicroPhotoService.getGpioInt(112);
        String[] columns = { "bv", "bcv" };
        MatrixCursor matrixCursor = new MatrixCursor(columns, 1);
        matrixCursor.addRow(new Object[] { Integer.valueOf(bv), Integer.valueOf(bcv) });
        return matrixCursor;
    }

    private Cursor recoganizePicture(Uri uri, String selection, String[] selectionArgs) {

        String decodedSelection = stringFromBase64(selection);

        String paramPath = null;
        String binPath = null;
        String blobName8 = null;
        String blobName16 = null;
        String blobName32 = null;
        String path = null;

        if (!TextUtils.isEmpty(decodedSelection)) {
            Uri u = Uri.parse("http://a.com/?" + decodedSelection);
            paramPath = u.getQueryParameter("param");
            binPath = u.getQueryParameter("bin");
            blobName8 = u.getQueryParameter("b8");
            blobName16 = u.getQueryParameter("b16");
            blobName32 = u.getQueryParameter("b32");
            path = u.getQueryParameter("path");
        }

        if (TextUtils.isEmpty(paramPath) || TextUtils.isEmpty(binPath) || TextUtils.isEmpty(blobName8) ||
                TextUtils.isEmpty(blobName16) || TextUtils.isEmpty(blobName32) || TextUtils.isEmpty(path)) {
            return null;
        }

        int[] data = MicroPhotoService.recoganizePicture(paramPath, binPath, blobName8, blobName16, blobName32, path);
        if (data == null || data.length == 0) {
            return null;
        }

        int rows = data.length / 6;
        if (rows == 0) {
            return null;
        }

        String[] columns = { "x", "y", "w", "h", "label", "prob" };
        MatrixCursor matrixCursor = new MatrixCursor(columns, rows);
        int idx = 0;
        for (int row = 0; row < rows; row++) {

            matrixCursor.addRow(new Object[] { Integer.valueOf(data[idx]), Integer.valueOf(data[idx + 1]), Integer.valueOf(data[idx + 2]),
                    Integer.valueOf(data[idx + 3]), Integer.valueOf(data[idx + 4]), Integer.valueOf(data[idx + 5])});
            idx += 6;
        }

        return matrixCursor;
    }

    private int importPrivateKey(Uri uri, ContentValues values) {
        String cert = values.containsKey("cert") ? values.getAsString("cert") : null;
        String path = values.containsKey("path") ? values.getAsString("path") : null;
        String resultFile = values.containsKey("resultFile") ? values.getAsString("resultFile") : null;
        int index = values.containsKey("index") ? values.getAsInteger("index").intValue() : 0;

        Log.i(TAG, "Start import private key");
        boolean res = false;
        if (!TextUtils.isEmpty(cert)) {
            // Import
            byte[] content = Base64.decode(cert, Base64.DEFAULT);
            if (content != null) {
                res = MicroPhotoService.importPrivateKey(index, content);
            }
        } else if (TextUtils.isEmpty(path)) {
            String md5 = values.containsKey("md5") ? values.getAsString("md5") : null;
            File file = new File(path);
            if (file.exists() && file.isFile()) {
                res = MicroPhotoService.importPrivateKeyFile(index, path, md5);
            }
        }

        Log.i(TAG, "Finish import private key");

        if (!TextUtils.isEmpty(resultFile)) {
            FilesUtils.ensureParentDirectoryExisted(resultFile);
            FilesUtils.writeTextFile(resultFile, res ? "1" : "0");
        }

        return res ? 1 : 0;
    }

    private int importPublicKey(Uri uri, ContentValues values) {
        String cert = values.containsKey("cert") ? values.getAsString("cert") : null;
        String path = values.containsKey("path") ? values.getAsString("path") : null;
        String resultFile = values.containsKey("resultFile") ? values.getAsString("resultFile") : null;
        int index = values.containsKey("index") ? values.getAsInteger("index").intValue() : 0;

        boolean res = false;
        if (!TextUtils.isEmpty(cert)) {
            // Import
            byte[] content = Base64.decode(cert, Base64.DEFAULT);
            if (content != null) {
                res = MicroPhotoService.importPublicKey(index, content);
            }
        } else if (TextUtils.isEmpty(path)) {
            String md5 = values.containsKey("md5") ? values.getAsString("md5") : null;
            File file = new File(path);
            if (file.exists() && file.isFile()) {
                res = MicroPhotoService.importPublicKeyFile(index, path, md5);
            }
        }

        if (!TextUtils.isEmpty(resultFile)) {
            FilesUtils.ensureParentDirectoryExisted(resultFile);
            FilesUtils.writeTextFile(resultFile, res ? "1" : "0");
        }

        return res ? 1 : 0;
    }

    private int genKeys(Uri uri, ContentValues values) {
        int index = values.containsKey("index") ? values.getAsInteger("index").intValue() : 0;
        String resultFile = values.containsKey("resultFile") ? values.getAsString("resultFile") : null;
        boolean res = MicroPhotoService.genKeys(index);

        if (!TextUtils.isEmpty(resultFile)) {
            FilesUtils.ensureParentDirectoryExisted(resultFile);
            FilesUtils.writeTextFile(resultFile, res ? "1" : "0");
        }

        return res ? 1 : 0;
    }

    private int genCertReq(Uri uri, ContentValues values) {
        int index = values.containsKey("index") ? values.getAsInteger("index").intValue() : 0;
        int type = values.containsKey("type") ? values.getAsInteger("type").intValue() : 0;
        String subject = values.containsKey("subject") ? values.getAsString("subject") : null;
        String path = values.containsKey("path") ? values.getAsString("path") : null;

        if (TextUtils.isEmpty(subject) || TextUtils.isEmpty(path)) {
            return 0;
        }

        boolean res = MicroPhotoService.genCertRequest(index, type, subject, path);
        return res ? 1 : 0;
    }

    private String stringFromBase64(String decoded) {
        if (TextUtils.isEmpty(decoded)) {
            return null;
        }

        byte[] bytes = Base64.decode(decoded, Base64.DEFAULT);

        String str = null;
        try {
            str = new String(bytes, "UTF-8");
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return str;
    }

    private int takePhoto(Uri uri, ContentValues values) {
        String path = values.containsKey("path") ? values.getAsString("path") : null;
        int channel = values.containsKey("channel") ? values.getAsInteger("channel").intValue() : 1;
        int preset = values.containsKey("preset") ? values.getAsInteger("preset").intValue() : 0xFF;

        int width = values.containsKey("width") ? values.getAsInteger("width").intValue() : 0;
        int height = values.containsKey("height") ? values.getAsInteger("height").intValue() : 0;

        String leftTopOsd = stringFromBase64(values.containsKey("leftTopOsd") ? values.getAsString("leftTopOsd") : null);
        String rightTopOsd = stringFromBase64(values.containsKey("rightTopOsd") ? values.getAsString("rightTopOsd") : null);
        String rightBottomOsd = stringFromBase64(values.containsKey("rightBottomOsd") ? values.getAsString("rightBottomOsd") : null);
        String leftBottomOsd = stringFromBase64(values.containsKey("leftBottomOsd") ? values.getAsString("leftBottomOsd") : null);

        String appPath = MicroPhotoContext.buildMpAppDir(getContext());
        File configFile = new File(appPath);
        configFile = new File(configFile, "data/channels/" + Integer.toString(channel) + ".json");

        File tmpConfigFile = new File(appPath);
        tmpConfigFile = new File(tmpConfigFile, "tmp/" + Integer.toString(channel) + "-" + Long.toString(System.currentTimeMillis()) + ".json");

        if (configFile.exists()) {
            try {
                FilesUtils.copyFile(configFile, tmpConfigFile);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }

        JSONObject configJson = JSONUtils.loadJson(tmpConfigFile.getAbsolutePath());
        try {
            if (configJson == null) {
                configJson = new JSONObject();
            }
            if (width > 0) {
                configJson.put("resolutionCX", width);
            }
            if (height > 0) {
                configJson.put("resolutionCY", height);
            }

            JSONObject osdJson = configJson.getJSONObject("osd");
            if (osdJson == null) {
                osdJson = configJson.put("osd", new JSONObject());
            }
            osdJson.put("leftTop", TextUtils.isEmpty(leftTopOsd) ? "" : leftTopOsd);
            osdJson.put("rightTop", TextUtils.isEmpty(rightTopOsd) ? "" : rightTopOsd);
            osdJson.put("rightBottom", TextUtils.isEmpty(rightBottomOsd) ? "" : rightBottomOsd);
            osdJson.put("leftBottom", TextUtils.isEmpty(leftBottomOsd) ? "" : leftBottomOsd);

            JSONUtils.saveJson(tmpConfigFile.getAbsolutePath(), configJson);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        File file = new File(path);
        if (file.exists()) {
            file.delete();
        } else {
            FilesUtils.ensureParentDirectoryExisted(path);
        }

        MicroPhotoService.takePhoto(channel, preset, true, tmpConfigFile.getAbsolutePath(), path);
        if (tmpConfigFile.exists()) {
            tmpConfigFile.delete();
        }

        return 1;
    }

    private int takeVideo(Uri uri, ContentValues values) {
        String path = values.containsKey("path") ? values.getAsString("path") : null;
        int channel = values.containsKey("channel") ? values.getAsInteger("channel").intValue() : 1;
        int preset = values.containsKey("preset") ? values.getAsInteger("preset").intValue() : 0xFF;

        int width = values.containsKey("width") ? values.getAsInteger("width").intValue() : 0;
        int height = values.containsKey("height") ? values.getAsInteger("height").intValue() : 0;

        int quality = values.containsKey("quality") ? values.getAsInteger("quality").intValue() : 0;
        int cameraId = values.containsKey("cameraId") ? values.getAsInteger("cameraId").intValue() : -1;
        int duration = values.containsKey("duration") ? values.getAsInteger("duration").intValue() : 15;

        int orientation = values.containsKey("orientation") ? values.getAsInteger("orientation").intValue() : 0;

        long videoId = System.currentTimeMillis() / 1000;

        String leftTopOsd = stringFromBase64(values.containsKey("leftTopOsd") ? values.getAsString("leftTopOsd") : null);
        String rightTopOsd = stringFromBase64(values.containsKey("rightTopOsd") ? values.getAsString("rightTopOsd") : null);
        String rightBottomOsd = stringFromBase64(values.containsKey("rightBottomOsd") ? values.getAsString("rightBottomOsd") : null);
        String leftBottomOsd = stringFromBase64(values.containsKey("leftBottomOsd") ? values.getAsString("leftBottomOsd") : null);

        if (cameraId == -1) {
            cameraId = channel - 1;
        }

        Context context = getContext();

        Intent recordingIntent = MicroPhotoService.makeRecordingIntent(context,
                false, cameraId, videoId, duration, width, height, quality, orientation,
                leftTopOsd, rightTopOsd, rightBottomOsd, leftBottomOsd, path);

        recordingIntent.putExtra("resultType", 0);
        recordingIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

        context.startActivity(recordingIntent);

        return 1;
    }

    private int hdrPlus(Uri uri, ContentValues values) {
        int rotation = values.containsKey("rotation") ? values.getAsInteger("rotation").intValue() : -1;
        int frontCamera = values.containsKey("front") ? values.getAsInteger("front").intValue() : 0;
        String outputPath = values.containsKey("output") ? values.getAsString("output") : null;
        int numberOfCaptures = values.containsKey("captures") ? values.getAsInteger("captures").intValue() : 0;
        List<String> paths = new ArrayList<>();
        for (int idx = 0; idx < numberOfCaptures; idx++) {
            String key = "path" + Integer.toString(idx + 1);
            String path = values.containsKey(key) ? values.getAsString(key) : null;
            if (!TextUtils.isEmpty(path)) {
                paths.add(path);
            }
        }



        ApplicationInfo applicationInfo = null;
        Context context = getContext();
        try {
            applicationInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_SHARED_LIBRARY_FILES);
        } catch (Exception ex) {

        }

        Log.d(TAG, "nativeLibraryDir= " + applicationInfo.nativeLibraryDir);
        String exeFilePath = applicationInfo.nativeLibraryDir + '/' + "libhdrp.so";
        File hdrpFile = new File(exeFilePath);
        if (!hdrpFile.exists()) {
            return 0;
        }

        String cmd = exeFilePath + " " + Integer.toString(rotation) + " ";
        cmd += Integer.toString(frontCamera) + " ";
        cmd += outputPath + " " + TextUtils.join(" ", paths);

        String[] params = new String[]{""};
        File workDir = context.getFilesDir();
        int exitCode = 0;

        try {
            Process process = Runtime.getRuntime().exec(cmd, params, workDir.getAbsoluteFile());
            // Intrinsics.checkNotNullExpressionValue(process, "process");
            InputStream inputStream = process.getInputStream();
            BufferedReader reader = new BufferedReader((Reader)(new InputStreamReader(inputStream)));

            // StringBuilder stringBuilder = new StringBuilder();
            while(true) {
                String line = reader.readLine();
                if (line == null) {
                    exitCode = process.exitValue();
                    reader.close();
                    process.destroy();
                    break;
                }

                if (line != null) {
                    // this.outputCallback.invoke(var5);
                    Log.d("HDRPlus", line);
                    // stringBuilder.append(line);
                    // stringBuilder.append("\r\n");
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return 1;
    }
}