package tech.glinfo.enbao.common.utils;

import lombok.extern.slf4j.Slf4j;

import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.Random;

@Slf4j
public class AirKissEncoder {
    private int[] mEncodedData = new int[2 << 14];
    private int mLength = 0;

    // Random char should be in range [0, 127).
    private char mRandomChar = (char) (new Random().nextInt(0x7F));

    public AirKissEncoder(String ssid, String password) {
        int times = 5;
        String data = password + mRandomChar + ssid;
        try {
            data = new String(data.getBytes(), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        log.debug("###############data:{}", data);
        while (times-- > 0) {
            leadingPart();
            magicCode(ssid, password);
            for (int i = 0; i < 15; ++i) {
                prefixCode(password);
                int index;
                byte content[] = new byte[4];
                for (index = 0; index < data.getBytes().length / 4; ++index) {
                    System.arraycopy(data.getBytes(), index * 4, content, 0, content.length);
                    sequence(index, content);
                }
                if (data.getBytes().length % 4 != 0) {
                    content = new byte[data.getBytes().length % 4];
                    System.arraycopy(data.getBytes(), index * 4, content, 0, content.length);
                    sequence(index, content);

                }
            }
        }
    }

    public int[] getEncodedData() {
        return Arrays.copyOf(mEncodedData, mLength);
    }

    public int getRandomChar() {
        return mRandomChar;
    }

    private void appendEncodedData(int length) {
        mEncodedData[mLength++] = length;
    }

    private int CRC8(byte data[]) {
        int len = data.length;
        int i = 0;
        int crc = 0x00;
        while (len-- > 0) {
            int extract = data[i++];
            for (byte tempI = 8; tempI != 0; tempI--) {
                byte sum = (byte) ((crc & 0xFF) ^ (extract & 0xFF));
                sum = (byte) ((sum & 0xFF) & 0x01);
                crc = (byte) ((crc & 0xFF) >>> 1);
                if (sum != 0) {
                    crc = (byte)((crc & 0xFF) ^ 0x8C);
                }
                extract = (byte) ((extract & 0xFF) >>> 1);
            }
        }
        return (crc & 0xFF);
    }

    private int CRC8(String stringData) {
        return CRC8(stringData.getBytes());
    }

    private void leadingPart() {
        for (int i = 0; i < 50; ++i) {
            for (int j = 1; j <= 4; ++j)
                appendEncodedData(j);
        }
    }

    private void magicCode(String ssid, String password) {
        byte[] bSsid = ssid.getBytes();
        String u8Ssid = null;
        try {
            u8Ssid = new String(bSsid, "UTF-8" );
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        int length = u8Ssid.getBytes().length+ password.length()+1;
        int magicCode[] = new int[4];
        magicCode[0] = 0x00 | (length >>> 4 & 0xF);
        if (magicCode[0] == 0)
            magicCode[0] = 0x08;
        magicCode[1] = 0x10 | (length & 0xF);
        int crc8 = CRC8(u8Ssid);
        magicCode[2] = 0x20 | (crc8 >>> 4 & 0xF);
        magicCode[3] = 0x30 | (crc8 & 0xF);
        for (int i = 0; i < 20; ++i) {
            for (int j = 0; j < 4; ++j) {
//                System.out.println(magicCode[j]);
                appendEncodedData(magicCode[j]);
            }
        }
    }

    private void prefixCode(String password) {
        int length = password.length();
        int prefixCode[] = new int[4];
        prefixCode[0] = 0x40 | (length >>> 4 & 0xF);
        prefixCode[1] = 0x50 | (length & 0xF);
        int crc8 = CRC8(new byte[] {(byte)length});
        prefixCode[2] = 0x60 | (crc8 >>> 4 & 0xF);
        prefixCode[3] = 0x70 | (crc8 & 0xF);
        for (int j = 0; j < 4; ++j)
            appendEncodedData(prefixCode[j]);
    }

    private void sequence(int index, byte data[]) {
        byte content[] = new byte[data.length + 1];
        content[0] = (byte)(index & 0xFF);
        System.arraycopy(data, 0, content, 1, data.length);
        int crc8 = CRC8(content);
        appendEncodedData(0x80 | crc8);
        appendEncodedData(0x80 | index);
        for (byte aData : data) {
            int bData = (aData & 0xff);
            appendEncodedData(bData | 0x100);
        }
    }
}
