package net.northking.cctp.scriptcase.tools.hapUtil.resources;

import lombok.extern.slf4j.Slf4j;
import net.northking.cctp.scriptcase.tools.ByteUtils;
import net.northking.cctp.scriptcase.tools.InputStreamUtils;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;

@Slf4j
public class ResourcesIndex {
    private static final String HEADER_PREFIX = "Restool ";
    private final IndexHeader indexHeader = new IndexHeader();
    private LimitKeyConfig[] limitKeyConfigs = new LimitKeyConfig[0];
    private IdSet[] idSets = new IdSet[0];

    public ResourcesIndex(InputStream stream, long dataSize) throws IOException {
        DataInputStream dataInput = new DataInputStream(stream);

        byte[] headerBytes = new byte[0x80];
        try {
            dataInput.readFully(headerBytes);
        } catch (IOException e) {
            log.error("解析Hap文件resource.index时发生IO错误", e);
            return;
        }
        int stopIndex = -1;
        for (int i = 0; i < headerBytes.length; i++) {
            if (headerBytes[i] == 0) {
                stopIndex = i;
                break;
            }
        }
        if (stopIndex == -1) {
            throw new IOException("无法定位版本结束位置");
        }
        String header = new String(headerBytes, 0, stopIndex);
        String[] headers = header.split(" ");
        if (headers.length != 2) {
            throw new IOException("无法处理版本字符串：" + header);
        }
        indexHeader.version = headers[1];

        byte[] sizeByteArray = new byte[4];
        dataInput.readFully(sizeByteArray);
        int fileSize = ByteUtils.littleEndianByteArrayToInt(sizeByteArray);
        if (fileSize != dataSize) {
            throw new IOException("文件记录的大小与压缩包给定大小不一致");
        }
        indexHeader.fileSize = fileSize;

        dataInput.readFully(sizeByteArray);
        indexHeader.limitKeyConfigSize = ByteUtils.littleEndianByteArrayToInt(sizeByteArray);
        limitKeyConfigs = new LimitKeyConfig[indexHeader.limitKeyConfigSize];
        for (int i = 0; i < indexHeader.limitKeyConfigSize; i++) {
            LimitKeyConfig limitKeyConfig = new LimitKeyConfig();
            for (int j = 0; j < 4; j++) {
                dataInput.read();
            }
            dataInput.readFully(sizeByteArray);
            limitKeyConfig.offset = ByteUtils.littleEndianByteArrayToInt(sizeByteArray);
            dataInput.readFully(sizeByteArray);
            limitKeyConfig.keyCont = ByteUtils.littleEndianByteArrayToInt(sizeByteArray);
            limitKeyConfig.data = new KeyParam[limitKeyConfig.keyCont];
            for (int j = 0; j < limitKeyConfig.keyCont; j++) {
                KeyParam keyParam = new KeyParam();
                dataInput.readFully(sizeByteArray);
                keyParam.setType(ByteUtils.littleEndianByteArrayToInt(sizeByteArray));
                dataInput.readFully(sizeByteArray);
                keyParam.setValue(ByteUtils.littleEndianByteArrayToInt(sizeByteArray));
                limitKeyConfig.data[j] = keyParam;
            }
            limitKeyConfigs[i] = limitKeyConfig;
        }

        idSets = new IdSet[indexHeader.limitKeyConfigSize];
        for (int i = 0; i < indexHeader.limitKeyConfigSize; i++) {
            for (int j = 0; j < 4; j++) {
                dataInput.read();
            }
            IdSet idSet = new IdSet();
            dataInput.readFully(sizeByteArray);
            idSet.idCount = ByteUtils.littleEndianByteArrayToInt(sizeByteArray);
            idSet.idData = new IdSet.IdData[idSet.idCount];
            for (int j = 0; j < idSet.idCount; j++) {
                IdSet.IdData idData = new IdSet.IdData();
                dataInput.readFully(sizeByteArray);
                idData.id = ByteUtils.littleEndianByteArrayToInt(sizeByteArray);
                dataInput.readFully(sizeByteArray);
                idData.offset = ByteUtils.littleEndianByteArrayToInt(sizeByteArray);
                idSet.idData[j] = idData;
            }
            idSets[i] = idSet;
        }

        for (int i = 0; i < indexHeader.limitKeyConfigSize; i++) {
            IdSet idSet = idSets[i];
            idSet.recordItems = new RecordItem[idSet.idCount];
            for (int j = 0; j < idSet.idCount; j++) {
                RecordItem recordItem = new RecordItem();
                dataInput.readFully(sizeByteArray);
                recordItem.setSize(ByteUtils.littleEndianByteArrayToInt(sizeByteArray));
                dataInput.readFully(sizeByteArray);
                recordItem.setResType(ByteUtils.littleEndianByteArrayToInt(sizeByteArray));
                dataInput.readFully(sizeByteArray);
                recordItem.setId(ByteUtils.littleEndianByteArrayToInt(sizeByteArray));

                dataInput.readFully(sizeByteArray, 0, 2);
                int length = ByteUtils.littleEndianByteArrayToShort(sizeByteArray);
                recordItem.setValue(new String(InputStreamUtils.readNBytes(dataInput,length), 0, length - 1));
                dataInput.readFully(sizeByteArray, 0, 2);
                length = ByteUtils.littleEndianByteArrayToShort(sizeByteArray);
                recordItem.setName(new String(InputStreamUtils.readNBytes(dataInput,length), 0, length - 1));

                idSet.recordItems[j] = recordItem;

            }
        }

    }

    public IndexHeader getIndexHeader() {
        return indexHeader;
    }

    public RecordItem getRecordItemById(int id) {
        for (IdSet idSet : idSets) {
            for (RecordItem recordItem : idSet.recordItems) {
                if (recordItem.getId() == id) {
                    return recordItem;
                }
            }
        }
        return null;
    }
}
