package server

import (
	"database/sql"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"net/url"
	"testing"

	"github.com/stretchr/testify/require"
	"go.uber.org/zap"

	"github.com/status-im/status-go/logutils"
	"github.com/status-im/status-go/protocol/common"
	"github.com/status-im/status-go/protocol/protobuf"
	"github.com/status-im/status-go/protocol/sqlite"
)

func setupTest(t *testing.T) (*sql.DB, *zap.Logger) {
	dbPath, err := ioutil.TempFile("", "status-go-test-db-")
	require.NoError(t, err)

	db, err := sqlite.Open(dbPath.Name(), "", sqlite.ReducedKDFIterationsNumber)
	require.NoError(t, err)

	logger := logutils.ZapLogger()
	return db, logger
}

func createUserMessage(t *testing.T, db *sql.DB, msg *common.Message) {
	whisperTimestamp := 0
	source := ""
	text := ""
	contentType := 0
	timestamp := 0
	chatID := "1"
	localChatID := "1"
	responseTo := ""
	clockValue := 0

	stmt, err := db.Prepare(`
		INSERT INTO user_messages (
			id,
			whisper_timestamp,
			source,
			text,
			content_type,
			timestamp,
			chat_id,
			local_chat_id,
			response_to,
			clock_value,
			unfurled_links
		) VALUES (?,?,?,?,?,?,?,?,?,?,?)
	`)
	require.NoError(t, err)

	links, err := json.Marshal(msg.UnfurledLinks)
	require.NoError(t, err)

	_, err = stmt.Exec(
		msg.ID,
		whisperTimestamp,
		source,
		text,
		contentType,
		timestamp,
		chatID,
		localChatID,
		responseTo,
		clockValue,
		links,
	)
	require.NoError(t, err)
}

func httpGetReqRecorder(t *testing.T, handler http.HandlerFunc, reqURL string) *httptest.ResponseRecorder {
	req, err := http.NewRequest("GET", reqURL, nil)
	require.NoError(t, err)

	rr := httptest.NewRecorder()
	handler.ServeHTTP(rr, req)

	return rr
}

func TestHandleLinkPreviewThumbnail(t *testing.T) {
	db, logger := setupTest(t)
	previewURL := "https://github.com"

	msg := common.Message{
		ID: "1",
		ChatMessage: &protobuf.ChatMessage{
			UnfurledLinks: []*protobuf.UnfurledLink{
				{
					Type:             protobuf.UnfurledLink_LINK,
					Url:              previewURL,
					ThumbnailWidth:   100,
					ThumbnailHeight:  200,
					ThumbnailPayload: []byte{0xff, 0xd8, 0xff, 0xdb, 0x0, 0x84, 0x0, 0x50, 0x37, 0x3c, 0x46, 0x3c, 0x32, 0x50},
				},
			},
		},
	}
	createUserMessage(t, db, &msg)

	// Test happy path.
	reqURL := "/dummy?" + url.Values{"message-id": {msg.ID}, "url": {previewURL}}.Encode()
	rr := httpGetReqRecorder(t, handleLinkPreviewThumbnail(db, logger), reqURL)
	require.Equal(t, http.StatusOK, rr.Code)
	require.Equal(t, msg.UnfurledLinks[0].ThumbnailPayload, rr.Body.Bytes())
	require.Equal(t, "image/jpeg", rr.HeaderMap.Get("Content-Type"))
	require.Equal(t, "no-store", rr.HeaderMap.Get("Cache-Control"))

	// Test bad requests.
	reqURL = "/dummy?" + url.Values{"message-id": {msg.ID}}.Encode()
	rr = httpGetReqRecorder(t, handleLinkPreviewThumbnail(db, logger), reqURL)
	require.Equal(t, http.StatusBadRequest, rr.Code)
	require.Equal(t, "missing query parameter 'url'\n", rr.Body.String())

	reqURL = "/dummy?" + url.Values{"url": {previewURL}}.Encode()
	rr = httpGetReqRecorder(t, handleLinkPreviewThumbnail(db, logger), reqURL)
	require.Equal(t, http.StatusBadRequest, rr.Code)
	require.Equal(t, "missing query parameter 'message-id'\n", rr.Body.String())

	// Test mime type not supported.
	msg.UnfurledLinks[0].ThumbnailPayload = []byte("unsupported image")
	createUserMessage(t, db, &msg)
	reqURL = "/dummy?" + url.Values{"message-id": {msg.ID}, "url": {previewURL}}.Encode()
	rr = httpGetReqRecorder(t, handleLinkPreviewThumbnail(db, logger), reqURL)
	require.Equal(t, http.StatusNotImplemented, rr.Code)
}