package ch.threema.app.webclient.converter;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.msgpack.core.MessagePack;
import org.msgpack.core.MessageUnpacker;
import org.msgpack.value.Value;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import ch.threema.domain.protocol.csp.messages.file.FileData;
import ch.threema.storage.models.AbstractMessageModel;
import ch.threema.storage.models.MessageModel;
import ch.threema.storage.models.data.media.FileDataModel;

import static org.junit.Assert.assertEquals;

@SmallTest
@RunWith(AndroidJUnit4.class)
public class MessageTest {
    @Test
    public void testFixFileName() {
        // Fix file extension if missing
        assertEquals("file.jpg", Message.fixFileName("file", "image/jpeg"));
        assertEquals("file.png", Message.fixFileName("file", "image/png"));
        assertEquals("file.txt", Message.fixFileName("file", "text/plain"));

        // Ignore files containing a dot
        assertEquals("file.something", Message.fixFileName("file.something", "text/plain"));

        // Don't change existing extensions
        assertEquals("file.txt", Message.fixFileName("file.txt", "image/jpeg"));
    }

    private static String testMaybePutFileImpl(
        @NonNull String inputMimeType,
        @Nullable Instant createdAt,
        @Nullable String messageId
    ) throws IOException {
        // The Threema protocol does not require a file name in a file message,
        // but ARP does!
        final MsgpackObjectBuilder builder = new MsgpackObjectBuilder();
        final FileDataModel fileDataModel = new FileDataModel(
            inputMimeType,
            "image/jpeg",
            100,
            null,
            FileData.RENDERING_MEDIA,
            "A photo without name",
            true,
            new HashMap<>()
        );
        final AbstractMessageModel messageModel = new MessageModel();
        messageModel.setFileData(fileDataModel);
        messageModel.setCreatedAt(createdAt);
        messageModel.setApiMessageId(messageId);
        Message.maybePutFile(builder, "file", messageModel, fileDataModel);

        // Create Msgpack message
        final ByteBuffer buf = builder.consume();

        // Decode message again
        try (MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(buf)) {
            final Map<String, Value> map = new HashMap<>();
            for (Map.Entry<Value, Value> entry : unpacker.unpackValue().asMapValue().map().entrySet()) {
                map.put(entry.getKey().asStringValue().toString(), entry.getValue());
            }
            final Map<String, Value> fileData = new HashMap<>();
            for (Map.Entry<Value, Value> entry : map.get("file").asMapValue().map().entrySet()) {
                fileData.put(entry.getKey().asStringValue().toString(), entry.getValue());
            }
            return fileData.get("name").asStringValue().asString();
        }
    }

    @Test
    public void testMaybePutFile() throws IOException {
        assertEquals(
            "threema-20201212-000000-null.png",
            testMaybePutFileImpl(
                "image/png",
                LocalDateTime.of(2020, 12, 12, 0, 0).atZone(ZoneId.systemDefault()).toInstant(),
                null
            )
        );
        assertEquals(
            "threema-20100130-131400-msgidasdf.txt",
            testMaybePutFileImpl(
                "text/plain",
                LocalDateTime.of(2010, 1, 30, 13, 14).atZone(ZoneId.systemDefault()).toInstant(),
                "msgidasdf"
            )
        );
    }
}
