// Copyright Earl Warren <contact@earl-warren.org>
// Copyright Loïc Dachary <loic@dachary.org>
// SPDX-License-Identifier: MIT

package f3

import (
	"path/filepath"
	"strings"
	"testing"

	"github.com/santhosh-tekuri/jsonschema/v6"
	"github.com/stretchr/testify/assert"
)

func TestStoreLoad(t *testing.T) {
	tmpDir := t.TempDir()

	type S struct {
		A int
		B string
	}
	original := S{A: 1, B: "B"}
	p := filepath.Join(tmpDir, "s.json")
	assert.NoError(t, Store(p, original))
	var loaded S
	assert.NoError(t, Load(p, &loaded, false))
	assert.EqualValues(t, original, loaded)
}

func TestF3_CI(t *testing.T) {
	var ci CI
	err := Load("file_format_testdata/ci/good.json", &ci, true)
	assert.NoError(t, err)
	err = Load("file_format_testdata/ci/bad.json", &ci, true)
	assert.ErrorContains(t, err, "'/index': value must be one of")
}

func TestF3_User(t *testing.T) {
	var user User
	err := Load("file_format_testdata/user/good.json", &user, true)
	assert.NoError(t, err)
	err = Load("file_format_testdata/user/bad.json", &user, true)
	assert.ErrorContains(t, err, "missing properties 'index'")
}

func TestF3_Organization(t *testing.T) {
	var organization Organization
	err := Load("file_format_testdata/organization/good.json", &organization, true)
	assert.NoError(t, err)
	err = Load("file_format_testdata/organization/bad.json", &organization, true)
	assert.ErrorContains(t, err, "missing properties 'index'")
}

func TestF3_Project(t *testing.T) {
	var project Project
	err := Load("file_format_testdata/project/good.json", &project, true)
	assert.NoError(t, err)
	err = Load("file_format_testdata/project/bad.json", &project, true)
	assert.ErrorContains(t, err, "'/stars': got string, want number")
}

func TestF3_Issue(t *testing.T) {
	var issue Issue
	err := Load("file_format_testdata/issue/good.json", &issue, true)
	assert.NoError(t, err)
	err = Load("file_format_testdata/issue/bad.json", &issue, true)
	assert.ErrorContains(t, err, "missing property 'index'")
}

func TestF3_PullRequest(t *testing.T) {
	var pullRequest PullRequest
	err := Load("file_format_testdata/pullrequest/good.json", &pullRequest, true)
	assert.NoError(t, err)
	err = Load("file_format_testdata/pullrequest/bad.json", &pullRequest, true)
	assert.ErrorContains(t, err, "missing properties 'index'")
}

func TestF3_Release(t *testing.T) {
	var release Release
	err := Load("file_format_testdata/release/good.json", &release, true)
	assert.NoError(t, err)
	err = Load("file_format_testdata/release/bad.json", &release, true)
	assert.ErrorContains(t, err, "missing properties 'index'")
}

func TestF3_Attachment(t *testing.T) {
	var attachment Attachment
	err := Load("file_format_testdata/attachment/good.json", &attachment, true)
	assert.NoError(t, err)
	err = Load("file_format_testdata/attachment/bad.json", &attachment, true)
	assert.ErrorContains(t, err, "missing properties 'index'")
}

func TestF3_Comment(t *testing.T) {
	var comment Comment
	err := Load("file_format_testdata/comment/good.json", &comment, true)
	assert.NoError(t, err)
	err = Load("file_format_testdata/comment/bad.json", &comment, true)
	assert.ErrorContains(t, err, "'/created': 'AAAAAAAAA' is not valid date-time")
}

func TestF3_Label(t *testing.T) {
	var label Label
	err := Load("file_format_testdata/label/good.json", &label, true)
	assert.NoError(t, err)
	err = Load("file_format_testdata/label/bad.json", &label, true)
	assert.ErrorContains(t, err, "'/exclusive': got string, want boolean")
}

func TestF3_Milestone(t *testing.T) {
	var milestone Milestone
	err := Load("file_format_testdata/milestone/good.json", &milestone, true)
	assert.NoError(t, err)
	err = Load("file_format_testdata/milestone/bad.json", &milestone, true)
	assert.ErrorContains(t, err, "missing properties 'index'")
}

func TestF3_Review(t *testing.T) {
	var review Review
	err := Load("file_format_testdata/review/good.json", &review, true)
	assert.NoError(t, err)
	err = Load("file_format_testdata/review/bad.json", &review, true)
	assert.ErrorContains(t, err, "missing properties 'index'")
}

func TestF3_Reaction(t *testing.T) {
	var reaction Reaction
	err := Load("file_format_testdata/reaction/good.json", &reaction, true)
	assert.NoError(t, err)
	err = Load("file_format_testdata/reaction/bad.json", &reaction, true)
	assert.ErrorContains(t, err, "missing properties 'index'")
}

func TestF3_Repository(t *testing.T) {
	var repository Repository
	err := Load("file_format_testdata/repository/good.json", &repository, true)
	assert.NoError(t, err)
	err = Load("file_format_testdata/repository/bad.json", &repository, true)
	assert.ErrorContains(t, err, "missing property 'name'")
}

func TestF3_ReviewComment(t *testing.T) {
	var reviewComment ReviewComment
	err := Load("file_format_testdata/reviewcomment/good.json", &reviewComment, true)
	assert.NoError(t, err)
	err = Load("file_format_testdata/reviewcomment/bad.json", &reviewComment, true)
	assert.ErrorContains(t, err, "missing properties 'index'")
}

func TestF3_Topic(t *testing.T) {
	var topic Topic
	err := Load("file_format_testdata/topic.json", &topic, true)
	assert.NoError(t, err)
}

func TestF3_ValidationFail(t *testing.T) {
	var issue Issue
	err := Load("file_format_testdata/issue/bad.json", &issue, true)
	if _, ok := err.(*jsonschema.ValidationError); ok {
		errors := strings.Split(err.(*jsonschema.ValidationError).GoString(), "\n")
		assert.Contains(t, errors[1], "missing property")
	} else {
		t.Fatalf("got: type %T with value %s, want: *jsonschema.ValidationError", err, err)
	}
}
