package cordova.plugin.netcontroll.integration;

import org.apache.cordova.CallbackContext;

//Json Serialize
import android.app.Activity;
import android.content.Context;
import android.os.Environment;
import android.util.Base64;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.SerializedName;
import com.google.zxing.WriterException;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.BarcodeFormat;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.HashMap;
import java.util.Map;

import com.google.zxing.EncodeHintType;

import android.os.AsyncTask;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import java.lang.reflect.Type;
import java.util.ArrayList;

import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import java.util.EnumMap;

import com.izettle.html2bitmap.Html2Bitmap;
import com.izettle.html2bitmap.content.WebViewContent;

import java.io.ByteArrayOutputStream;

import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;

public class NetControllPrinter {
    private static final int PERMISSIONS_REQUEST_CODE = 0x1234;

    //Converter Texto Impresso para HTML

    public static boolean EnviarAberturaGaveta(String linhasImpressos) {
        try {
            boolean result = false;
            String[] linhas = linhasImpressos.split("\n");
            for (String item : linhas) {
                if (item.contains("<g>") && item.contains("</g>")) {
                    result = true;
                    break;
                }
            }
            return result;
        } catch (Exception ex) {
            throw ex;
        }
    }

    public static String ConverterTextoImpressoToHtml(String linhasImpressos) {
        try {
            String htmlStr = NetControllPrinter.ConverterImpressaoToHtmlInicio();

            List<String> linhas = NetControllPrinter.ConverterImpressaoToHtmlLinhasHtml(linhasImpressos);

            for (String linha : linhas) {
                htmlStr += linha;
            }

            htmlStr += NetControllPrinter.ConverterImpressaoToHtmlFinal();

            return htmlStr;
        } catch (Exception e) {
            throw e;
        }
    }

    private static String ConverterImpressaoToHtmlInicio() {
        String htmlResult = "<!DOCTYPE html>\n" +
                "<html lang='en'>\n" +
                "\n" +
                "<head>\n" +
                "    <!--  <meta charset='UTF-8'>\n" +
                "    <meta http-equiv='X-UA-Compatible' content='IE=edge'>\n" +
                "    <meta name='viewport' content='width=380, initial-scale=1.0'>\n" +
                "    <title>Document</title> -->\n" +
                "\n" +
                "    <style>\n" +
                "        /* @media print {\n" +
                "            .printer-ticket {\n" +
                "                border: none !important;\n" +
                "            }\n" +
                "        } */\n" +
                "\n" +
                "        body {\n" +
                "            margin: 0px;\n" +
                "            width: 380px;\n" +
                "            /*border: 1px solid black;*/\n" +
                "        }\n" +
                "\n" +
                "\n" +
                "\n" +
                "        .printer-ticket {\n" +
                "            /* background-color: #ffffcc; */\n" +
                "            background-color: white;\n" +
                "            font-size: 16px;\n" +

                "            /* padding: 10px; */\n" +
                "            max-width: 380px;\n" +
                "            /* border: solid 1px black; */\n" +
                "            /* text-align: center; */\n" +
                "            /*padding-left: 10px;*/\n" +
                "            /*padding-right: 10px;*/\n" +
                "        }\n" +
                "\n" +
                "        /* @media (max-width: 979px) {\n" +
                "            .section-printer--ticket {\n" +
                "                position: initial;\n" +
                "                top: 0;\n" +
                "            }\n" +
                "        } */\n" +
                "\n" +
                "        .printer-ticket table {\n" +
                "            margin: auto;\n" +
                "\n" +
                "        }\n" +
                "\n" +
                "        .printer-ticket * {\n" +
                "            font-family: monospace;\n" +
                "            /* font-family: Consolas, Regular;*/\n" +
                "            /* font-size: 100%; */\n" +
                "            color: black;\n" +
                "            /* line-height: 80%; */\n" +
                "            max-width: 380px;\n" +
                "            /* line-height: normal; */\n" +
                "            /* padding-left: 15px; */\n" +
                "        }\n" +
                "\n" +
                "        [data-normal='true'] {\n" +
                "            /* letter-spacing: 1px;\n" +
                "            font-size: 30px;\n" +
                "            text-align: left; */\n" +
                "            /* padding-left: 15px; */\n" +
                "        }\n" +
                "\n" +
                "\n" +
                "        [data-expandido='true'] {\n" +
                "            letter-spacing: 1px;\n" +
                "            font-size: 30px !important;\n" +
                "            /* text-align: left !important; */\n" +
                "            /* padding-left: 15px; */\n" +
                "        }\n" +
                "\n" +
                "        [data-condensado='true'] {\n" +
                "            letter-spacing: -2px;\n" +
                "            font-size: 15px !important;\n" +
                "            /* text-align: left !important; */\n" +
                "            /* padding-left: 10px; */\n" +
                "        }\n" +
                "\n" +
                "        [data-negrito='true'] {\n" +
                "            font-weight: bold;\n" +
                "        }\n" +
                "\n" +
                "        [data-reverse='true'] {\n" +
                "            background-color: black !important;\n" +
                "            color: white;\n" +
                "            -webkit-print-color-adjust: exact;\n" +
                "        }\n" +
                "\n" +
                "        [data-qrcode='true'] {\n" +
                "            text-align: center;\n" +
                "        }\n" +
                "\n" +
                "        [data-barcode128='true'] {\n" +
                "            text-align: center;\n" +
                "        }\n" +
                "\n" +
                "\n" +
                "        [data-alinhamento='1'] {\n" +
                "            text-align: left;\n" +
                "        }\n" +
                "\n" +
                "        [data-alinhamento='2'] {\n" +
                "            text-align: center;\n" +
                "        }\n" +
                "\n" +
                "        [data-alinhamento='3'] {\n" +
                "            text-align: right;\n" +
                "        }\n" +
                "    </style>\n" +
                "</head>\n" +
                "\n" +
                "<body>\n" +
                "\n" +
                "\n" +
                "    <div class='printer-ticket'>\n" +
                "        <div class='row'>\n";

        return htmlResult;
    }

    private static List<String> ConverterImpressaoToHtmlLinhasHtml(String textoImpresso) {
        List<String> result = new ArrayList<String>();
        try {
            String[] linhas = textoImpresso.split("\n");
            for (String item : linhas) {
                String linha = item.replace(".nomeponto", "");
                linha = linha.replace(".impressovia", "");
                String tipoCaracter = "feed";

                if (linha.contains("<n>") && linha.contains("</n>")) {
                    tipoCaracter = "normal";
                    linha = linha.replace("<n>", "").replace("</n>", "");
                    if (linha.contains("<b>") && linha.contains("</b>")) {
                        tipoCaracter += "-bold";
                        linha = linha.replace("<b>", "").replace("</b>", "");
                    }
                } else if (linha.contains("<g>") && linha.contains("</g>")) {
                    tipoCaracter = "drawer";
                } else if (linha.contains("<e>") && linha.contains("</e>")) {
                    tipoCaracter = "expanded";
                    linha = linha.replace("<e>", "").replace("</e>", "");
                    if (linha.contains("<n>") && linha.contains("</n>")) {
                        tipoCaracter += "-normal";
                        linha = linha.replace("<n>", "").replace("</n>", "");
                        if (linha.contains("<b>") && linha.contains("</b>")) {
                            tipoCaracter = "bold";
                            linha = linha.replace("<b>", "").replace("</b>", "");
                        }
                    }
                } else if (linha.contains("<b>") && linha.contains("</b>")) {
                    tipoCaracter = "bold";
                    linha = linha.replace("<b>", "").replace("</b>", "");
                    if (linha.contains("<c>") && linha.contains("</c>")) {
                        tipoCaracter += "-condensed";
                        linha = linha.replace("<c>", "").replace("</c>", "");
                    } else if (linha.contains("<n>") && linha.contains("</n>")) {
                        tipoCaracter += "-normal";
                        linha = linha.replace("<n>", "").replace("</n>", "");
                    }
                } else if (linha.contains("<c>") && linha.contains("</c>")) {
                    tipoCaracter = "condensed";
                    linha = linha.replace("<c>", "").replace("</c>", "");
                } else if (linha.contains("<f>") && linha.contains("</f>")) {
                    tipoCaracter = "reverse";
                    linha = linha.replace("<f>", "").replace("</f>", "");
                } else if (linha.contains("<ce>") && linha.contains("</ce>")) {
                    linha = linha.replace("<ce>", "").replace("</ce>", "");
                    if (linha.contains("<qrcode>") && linha.contains("</qrcode>")) {
                        tipoCaracter = "qrcode";
                        linha = linha.replace("<qrcode>", "").replace("</qrcode>", "");
                    } else if (linha.contains("<code128>") && linha.contains("</code128>")) {
                        tipoCaracter = "barcode128";
                        linha = linha.replace("<code128>", "").replace("</code128>", "");
                    }
                }
                if (linha.contains("<esc      pos>")) {
                    linha = linha.replace("<esc      pos>", "              ");
                }
                if (linha == "") {
                    tipoCaracter = "feed";
                }

                switch (tipoCaracter) {
                    case "normal":
                        result.add(ImpressaoTextoNetPrintHelper_ImpressaoTextoDivRow(linha, false, false, false, false, false, false));
                        break;
                    case "normal-bold":
                        result.add(ImpressaoTextoNetPrintHelper_ImpressaoTextoDivRow(linha, false, false, true, false, false, false));
                        break;
                    case "bold-normal":
                        result.add(ImpressaoTextoNetPrintHelper_ImpressaoTextoDivRow(linha, false, false, true, false, false, false));
                        break;
                    case "bold":
                        result.add(ImpressaoTextoNetPrintHelper_ImpressaoTextoDivRow(linha, false, false, true, false, false, false));
                        break;
                    case "expanded":
                        result.add(ImpressaoTextoNetPrintHelper_ImpressaoTextoDivRow(linha, true, false, false, false, false, false));
                        break;
                    case "condensed":
                        result.add(ImpressaoTextoNetPrintHelper_ImpressaoTextoDivRow(linha, false, true, false, false, false, false));
                        break;
                    case "bold-condensed":
                        result.add(ImpressaoTextoNetPrintHelper_ImpressaoTextoDivRow(linha, false, true, true, false, false, false));
                        break;
                    case "reverse":
                        // ImpressaoTextoNetPrintHelper_ImpressaoTexto(linha, 1, 8 + 4, 0);
                        result.add(ImpressaoTextoNetPrintHelper_ImpressaoTextoDivRow(linha, true, false, true, true, false, false));
                        break;
                    case "drawer":
                        //ImpressaoTextoNetPrintHelper_AbreGavetaElgin();
                        break;
                    case "qrcode":
                        result.add(ImpressaoTextoNetPrintHelper_ImpressaoTextoDivRow(linha, false, false, false, false, false, true));
                        result.add(ImpressaoTextoNetPrintHelper_ImpressaoTextoDivRow("<br/>", false, false, false, false, false, false));
                        //ImpressaoTextoNetPrintHelper_DefinirImpressao(1);
                        //ImpressaoTextoNetPrintHelper_PrintQrCode(linha, 5, 1);
                        //ImpressaoTextoNetPrintHelper_AvancaPapel(5);
                        break;
                    case "barcode128":
                        result.add(ImpressaoTextoNetPrintHelper_ImpressaoTextoDivRow(linha, false, false, false, false, true, false));
                        result.add(ImpressaoTextoNetPrintHelper_ImpressaoTextoDivRow("<br/>", false, false, false, false, false, false));
                        //ImpressaoTextoNetPrintHelper_DefinirImpressao(1);
                        //ImpressaoTextoNetPrintHelper_PrintBarCode(8, "{C" + linha, 50, 2, 4);
                        //ImpressaoTextoNetPrintHelper_AvancaPapel(5);
                        break;

                    default:
                        result.add(ImpressaoTextoNetPrintHelper_ImpressaoTextoDivRow("<br/>", false, false, false, false, false, false));
                        //                        ImpressaoTextoNetPrintHelper_AvancaPapel(1);
                        break;
                }

            }
        } catch (Exception ex) {
            String errorStr = ex.toString();
            throw ex;
        }
        return result;
    }

    private static String ImpressaoTextoNetPrintHelper_ImpressaoTextoDivRow(String texto, boolean expandido, boolean condensado, boolean negrito, boolean reverse, boolean barCode, boolean qrCode) {
        String result = "";
        try {
            if (!qrCode && !barCode) {
                texto = texto.replace(" ", "&nbsp;").replace("\r", "");
            }

            String textoExpandido = "";
            if (expandido) {
                textoExpandido = " data-expandido='true'";
            }

            String textoCondensado = "";
            if (condensado) {
                textoCondensado = " data-condensado='true'";
            }

            String textoNegrito = "";
            if (negrito) {
                textoNegrito = " data-negrito='true'";
            }

            String textoReverse = "";
            if (reverse) {
                textoReverse = " data-reverse='true'";
            }

            String textoBarCode = "";
            if (barCode) {
                textoBarCode = " data-barcode128='true'";
                String base64Barcode128 = NetControllPrinter.CreateBarCodeBase64(texto, BarcodeFormat.CODE_128, 150, 75);
                String textoBarcode128 = "<img src=\"data:image/png;base64," + base64Barcode128 + "\" >";
                texto = textoBarcode128;
            }

            String textoQrCode = "";
            if (qrCode) {
                textoQrCode = " data-qrcode='true'";

                String baseQrCodeBase64 = NetControllPrinter.CreateBarCodeBase64(texto, BarcodeFormat.QR_CODE, 200, 200);
                String textoQrCodeResult = "<img src=\"data:image/png;base64," + baseQrCodeBase64 + "\" >";
                texto = textoQrCodeResult;

            }

            result = "<div class='row'>\n" +
                    "                    <div class='col-12' " + textoExpandido + textoCondensado + textoNegrito + textoReverse + textoBarCode + textoQrCode + " >" + texto + "</div>\n" +
                    "                </div>";
            return result;
        } catch (Exception ex) {
            throw ex;
        }
    }

    private static String ConverterImpressaoToHtmlFinal() {
        String htmlResult = " </div> " +
                "</div>" +
                "</body>" +
                "</html>";

        return htmlResult;
    }

    //Converter Html para Imagem
    public interface ConverterHtmlToBitmapCallBack {
        void onCallback(Bitmap bitmapResult);
    }

    public static void ConverterHtmlToBitmap(String htmlString, Context mContext, ConverterHtmlToBitmapCallBack callBack) {
        try {
            AsyncTask<Void, Void, Bitmap> taskBitMap = new AsyncTask<Void, Void, Bitmap>() {
                @Override
                protected Bitmap doInBackground(Void... voids) {
                    Html2Bitmap build = new Html2Bitmap.Builder().setContext(mContext).setContent(WebViewContent.html(htmlString)).setBitmapWidth(380).setMeasureDelay(300).setScreenshotDelay(300).setStrictMode(true).setTimeout(15).setTextZoom(96).build();
                    Bitmap bitmapResult = build.getBitmap();
                    return bitmapResult;
                }

                //
                @Override
                protected void onPostExecute(Bitmap bitmap) {
                    callBack.onCallback(bitmap);
                }

            }.execute();
        } catch (Exception e) {
            throw e;
        }
    }


    //Converter Salvar Imagem
    public static String SaveImage(Bitmap bitmap, @NonNull String directoryFileName) throws IOException {
        String result = "";
        try {
            boolean saved;
            OutputStream fos;

//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
//            ContentResolver resolver = mContext.getContentResolver();
//            ContentValues contentValues = new ContentValues();
//            contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, name);
//            contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/bitmap");
//            contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, "DCIM/" + IMAGES_FOLDER_NAME);
//            Uri imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
//            fos = resolver.openOutputStream(imageUri);
//        } else {
//        String imagesDir = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Download/download.png";
            String imagesDir = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Download/";
//            String imagesDir = Environment.getExternalStoragePublicDirectory(
//                    Environment.DIRECTORY_DCIM).toString() + File.separator + IMAGES_FOLDER_NAME;

            File file = new File(directoryFileName);

            if (file.exists()) {
                file.delete();
            }

//            if (!file.exists()) {
//                file.mkdir();
//            }

            File image = new File(directoryFileName);
            fos = new FileOutputStream(image);
//        }
            saved = bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
            fos.flush();
            fos.close();
            if (saved) {
                result = directoryFileName;
            }
            return result;
        } catch (Exception ex) {
            String exStr = ex.toString();
            throw ex;
        }
    }


    //Criar BarCode Base64
    public static String CreateBarCodeBase64(String valor, BarcodeFormat barcodeFormat, int width, int height) {
        ErrorCorrectionLevel errCorLvl = ErrorCorrectionLevel.L;
        switch (48) {
            case 48:
                errCorLvl = ErrorCorrectionLevel.L;
                break;
            case 49:
                errCorLvl = ErrorCorrectionLevel.M;
                break;
            case 50:
                errCorLvl = ErrorCorrectionLevel.Q;
                break;
            case 51:
                errCorLvl = ErrorCorrectionLevel.H;
        }

        Map<EncodeHintType, Object> hints = new EnumMap(EncodeHintType.class);
        hints.put(EncodeHintType.ERROR_CORRECTION, errCorLvl);

        Bitmap bitmap = null;
        try {
            bitmap = CreateBarcodeBitmap(valor, barcodeFormat, width, height, hints);
        } catch (WriterException e) {
            e.printStackTrace();
        }
        String resultBase64 = ConverterBitmapToBase64(bitmap);
        return resultBase64;
    }

    //Criar BarCode Bitmap
    public static Bitmap CreateBarcodeBitmap(String dados, BarcodeFormat tipo, int width, int height, Map<EncodeHintType, Object> hints) throws WriterException {
        int BLACK = -16777216;
        boolean WHITE = true;
        if (hints != null) {
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
            hints.put(EncodeHintType.MARGIN, 0);
        }

        long dte = System.currentTimeMillis();

        BitMatrix matrix;
        try {
            matrix = (new MultiFormatWriter()).encode(dados, tipo, width, height, hints);
        } catch (IllegalArgumentException var29) {
            var29.printStackTrace();
            return null;
        }

        dte = System.currentTimeMillis() - dte;
        width = matrix.getWidth();
        height = matrix.getHeight();
        long dtm = System.currentTimeMillis();
        int[][] mPixels = new int[height][width];

        int minX;
        int maxX;
        for (minX = 0; minX < height; ++minX) {
            for (maxX = 0; maxX < width; ++maxX) {
                mPixels[minX][maxX] = matrix.get(maxX, minX) ? -16777216 : -1;
            }
        }

        dtm = System.currentTimeMillis() - dtm;
        minX = 2147483647;
        maxX = 0;
        int minY = 2147483647;
        int maxY = 0;
        long dtp = System.currentTimeMillis();

        for (int y = 0; y < height; ++y) {
            for (int x = 0; x < width; ++x) {
                if (mPixels[y][x] != -1) {
                    if (x < minX) {
                        minX = x;
                    }

                    if (x > maxX) {
                        maxX = x;
                    }

                    if (y < minY) {
                        minY = y;
                    }

                    if (y > maxY) {
                        maxY = y;
                    }
                }
            }
        }

        dtp = System.currentTimeMillis() - dtp;
        width = maxX - minX + 1;
        height = maxY - minY + 1;
        long dtr = System.currentTimeMillis();
        int[][] mTrimmedPixels = new int[height][width];
        int y = minY;

        for (int i = 0; y < maxY + 1 && i < height; ++i) {
            System.arraycopy(mPixels[y], minX, mTrimmedPixels[i], 0, width);
            ++y;
        }

        dtr = System.currentTimeMillis() - dtr;
        long dtv = System.currentTimeMillis();
        int[] vPixels = new int[width * height];

        for (y = 0; y < height; ++y) {
            int offset = y * width;
            System.arraycopy(mTrimmedPixels[y], 0, vPixels, offset, width);
        }

        dtv = System.currentTimeMillis() - dtv;
        //        long dtb = System.currentTimeMillis();
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        bitmap.setPixels(vPixels, 0, width, 0, 0, width, height);
        return bitmap;
    }

    //Bitmap para Base64
    public static String ConverterBitmapToBase64(Bitmap bitmap) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
        byte[] byteArray = byteArrayOutputStream.toByteArray();
        String encoded = Base64.encodeToString(byteArray, Base64.DEFAULT);
        return encoded;
    }

    //Bitmap para ArrayBytes
    public static byte[] ConverterBitmapToArrayBytes(Bitmap bitmap) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
        byte[] byteArray = byteArrayOutputStream.toByteArray();
        return byteArray;
    }

    public static Bitmap ResizeBitmap(Bitmap source, int maxLength) {
        try {
                int targetWidth = maxLength;

                double aspectRatio = ((double) source.getHeight()) / ((double) source.getWidth());
                int targetHeight = (int) (targetWidth * aspectRatio);

                Bitmap result = Bitmap.createScaledBitmap(source, targetWidth, targetHeight, false);
                return result;
        }
        catch (Exception e)
        {
            return source;
        }
    }

    // Permissoes
    public static void RequestPermissions(Activity mActivity, Context mContext) {

        String[] missingPermissions = null;

        missingPermissions = FilterMissingPermissions(GetManifestPermissions(mContext), mContext);

        if (missingPermissions != null && missingPermissions.length > 0) {
            ActivityCompat.requestPermissions(mActivity, missingPermissions, PERMISSIONS_REQUEST_CODE);
        } else {
            String shotMessageStr = "showMessage();";
        }
    }

    private static String[] FilterMissingPermissions(String[] permissions, Context mContext) {
        String[] missingPermissions = null;
        List<String> list = null;

        list = new ArrayList<>();

        if (permissions != null && permissions.length > 0) {
            for (String permission : permissions) {
                if (ContextCompat.checkSelfPermission(mContext.getApplicationContext(), permission) != PackageManager.PERMISSION_GRANTED) {
                    list.add(permission);
                }
            }
        }

        missingPermissions = list.toArray(new String[0]);

        return missingPermissions;
    }

    private static String[] GetManifestPermissions(Context mContext)  {
        String[] permissions = null;
        PackageInfo info = null;

        try {
            info = mContext.getPackageManager().getPackageInfo(mContext.getApplicationContext().getPackageName(), PackageManager.GET_PERMISSIONS);
            permissions = info.requestedPermissions;
        } catch (PackageManager.NameNotFoundException ex) {
            try {
                throw ex;
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
        }

        if (permissions == null) {
            permissions = new String[0];
        }

        return permissions;
    }
}