package handlers_test

import (
	"fmt"
	"net/http"
	"otaupdate/handlers"
	"otaupdate/services"
	"testing"

	"github.com/fiskerinc/cloud-services/pkg/db/queries/mocks"
	"github.com/fiskerinc/cloud-services/pkg/s3"
	smock "github.com/fiskerinc/cloud-services/pkg/s3/mock"
	th "github.com/fiskerinc/cloud-services/pkg/testhelper"
)

func TestUpdateManifestFileAdd(t *testing.T) {
	formData := `--XXXXXX
Content-Disposition: form-data; name="manifest_ecu_id"

1000
--XXXXXX
Content-Disposition: form-data; name="offset"

1111
--XXXXXX
Content-Disposition: form-data; name="version"

2000
--XXXXXX
Content-Disposition: form-data; name="checksum"

CE114E45
--XXXXXX
Content-Disposition: form-data; name="order"

1
--XXXXXX
Content-Disposition: form-data; name="type"

01 Bootloader
--XXXXXX
Content-Disposition: form-data; name="signature"

53e976bd61161e4f425186e560f0797767d10fd6f0116e224efc444fa014754cb299e51827468c03c9b06508740ed738b1ec14b9cc753a1875971e335408660e
`

	missingFile := fmt.Sprintf(`%v--XXXXXX--
`, formData)

	badFile := fmt.Sprintf(`%v--XXXXXX
Content-Disposition: form-data; name="file"; filename="test.txt"
Content-Type: text/plain
Content-Length: 0

--XXXXXX--
`, formData)

	goodData := fmt.Sprintf(`%v--XXXXXX
Content-Disposition: form-data; name="file"; filename="test.txt"
Content-Type: text/plain

THIS IS A TEST FILE
--XXXXXX--
`, formData)

	compare := th.JSONComparer{
		IgnoreProps: []string{"file_id", "url"},
	}
	defer compare.Close()

	type TestCase struct {
		th.BasicHttpTest
		hasFileContent bool
		jsonCompare    bool
	}

	tests := []TestCase{
		{
			BasicHttpTest: th.BasicHttpTest{
				Name:             "No data",
				Request:          th.MakeTestMultipartRequest("http://example.com/manifestfile", "", "XXXXXX", nil),
				ExpectedStatus:   http.StatusBadRequest,
				ExpectedResponse: `{"message":"requires file","error":"Bad Request"}`,
			},
			hasFileContent: false,
		},
		{
			BasicHttpTest: th.BasicHttpTest{
				Name:             "Good data",
				Request:          th.MakeTestMultipartRequest("http://example.com/manifestfile", goodData, "XXXXXX", nil),
				ExpectedStatus:   http.StatusOK,
				ExpectedResponse: `{"file_id":"303ca940c940c645","manifest_ecu_id":1000,"filename":"test.txt","url":"https://upload-dev.fiskerdps.com/f453ae14-d89a-4e4f-9eae-fe7bcc456b55/test.txt","file_size":55,"checksum":"CE114E45","type":"bootloader","order":1,"write_region":{"offset":1111,"length":19}}`,
			},
			jsonCompare:    true,
			hasFileContent: true,
		},
		{
			BasicHttpTest: th.BasicHttpTest{
				Name:             "Missing file",
				Request:          th.MakeTestMultipartRequest("http://example.com/manifestfile", missingFile, "XXXXXX", nil),
				ExpectedStatus:   http.StatusBadRequest,
				ExpectedResponse: `{"message":"requires file","error":"Bad Request"}`,
			},
			hasFileContent: false,
		},
		{
			BasicHttpTest: th.BasicHttpTest{
				Name:             "Bad file",
				Request:          th.MakeTestMultipartRequest("http://example.com/manifestfile", badFile, "XXXXXX", nil),
				ExpectedStatus:   http.StatusBadRequest,
				ExpectedResponse: `{"message":"Length gt 0","error":"Bad Request"}`,
			},
			hasFileContent: false,
		},
	}

	for _, test := range tests {
		setup()
		w := th.ExecHTTPHandler(handlers.HandleUpdateManifestFileAdd, test.Request)

		if w.Result().StatusCode != test.ExpectedStatus {
			t.Errorf(th.TestErrorTemplate, test.Name, test.ExpectedStatus, w.Result().StatusCode)
		}

		if !test.jsonCompare && w.Body.String() != test.ExpectedResponse {
			t.Errorf(th.TestErrorTemplate, test.Name, test.ExpectedResponse, w.Body.String())
		}

		if test.jsonCompare {
			diff, err := compare.GetDiff([]byte(test.ExpectedResponse), w.Body.Bytes())
			if err != nil {
				t.Errorf(th.TestErrorTemplate, test.Name, nil, err)
			}
			for key, value := range diff {
				body := w.Body.String()
				fmt.Println(body)
				t.Errorf(th.TestErrorTemplate, test.Name, key, value)
			}
		}

		if test.hasFileContent {
			s3 := s3.GetS3().(*smock.S3Mock)
			content := string(s3.GetData())
			if len(content) == 0 {
				t.Errorf(th.TestErrorTemplate, test.Name, test.hasFileContent, fmt.Sprintf("Content size %v", len(content)))
			}
		}
	}
}

func setup() {
	// Setup mocks
	s3.SetS3Instance(&smock.S3Mock{})
	services.GetDB().SetFileKeys(&mocks.MockFileKeys{})
	services.GetDB().SetUpdateManifests(&mocks.MockUpdateManifests{})
}
