package Comment

import (
	"github.com/nspcc-dev/neo-go/pkg/interop/iterator"
	"github.com/nspcc-dev/neo-go/pkg/interop/native/std"
	"github.com/nspcc-dev/neo-go/pkg/interop/runtime"
	"github.com/nspcc-dev/neo-go/pkg/interop/storage"
)

type Comment struct {
	id        string
	userLogin string
	postId    string
	text      string
	likes     int
	dislikes  int
}

const (
	comment_prefix            = "comment_"
	user_comment_count_prefix = "comment_count_"
)

func _deploy(data interface{}, isUpdate bool) {
	ctx := storage.GetContext()
	storage.Put(ctx, "index_comment", "0")
}

func CreateNewComment(userLogin string, postId string, text string) {
	ctx := storage.GetContext()

	id := std.Atoi10(storage.Get(ctx, "index_comment").(string))
	id++
	storage.Put(ctx, "index_comment", std.Itoa10(id))

	if storage.Get(ctx, user_comment_count_prefix+userLogin) == nil {
		storage.Put(ctx, user_comment_count_prefix+userLogin, 0)
	}

	commentId := comment_prefix + std.Itoa10(id)
	newComment := Comment{
		id:        commentId,
		userLogin: userLogin,
		postId:    postId,
		text:      text,
		likes:     0,
		dislikes:  0,
	}
	var comments = make([]Comment, 0)
	comments = GetByPostId(postId)
	comments = append(comments, newComment)
	storage.Put(ctx, comment_prefix+postId, std.Serialize(comments)) // { "comment_post_{i} : comments.json"}
	storage.Put(ctx, commentId, std.Serialize(newComment))           // { "comment_{i}" : comment.json}

	commentCount := storage.Get(ctx, user_comment_count_prefix+userLogin).(int)
	commentCount++
	storage.Put(ctx, user_comment_count_prefix+userLogin, commentCount)   // { "comment_count_{login}" : {i} }
	storage.Put(ctx, userLogin+"_c_"+std.Itoa10(commentCount), commentId) // { "{login}_c_{i} : comment_{i} }

	runtime.Log("Comment created: " + commentId + " ----- " + user_comment_count_prefix + userLogin + " ------ " + userLogin + "_c_" + std.Itoa10(commentCount))
}

func GetByPostId(postId string) []Comment {
	ctx := storage.GetContext()
	comments := storage.Get(ctx, comment_prefix+postId)
	if comments == nil {
		storage.Put(ctx, comment_prefix+postId, std.Serialize(make([]Comment, 0)))
	}
	return std.Deserialize(storage.Get(ctx, comment_prefix+postId).([]byte)).([]Comment)
}

func GetByLoginInPost(postId string, login string) []Comment {
	comments := GetByPostId(postId)
	var commentsByAuthor []Comment
	for _, comment := range comments {
		if comment.userLogin == login {
			commentsByAuthor = append(commentsByAuthor, comment)
		}
	}

	return commentsByAuthor
}

func GetByLogin(login string) []Comment {
	var comments []Comment = make([]Comment, 0)
	ctx := storage.GetContext()
	it := storage.Find(ctx, login+"_c_", storage.ValuesOnly|storage.DeserializeValues)
	for iterator.Next(it) {
		commentId := iterator.Value(it).(string)
		comments = append(comments, GetComment(commentId))
	}

	return comments
}

func GetComment(commentId string) Comment {
	ctx := storage.GetContext()
	comment := storage.Get(ctx, commentId)
	if comment == nil {
		panic("comment not found")
	}
	return comment.(Comment)
}

func GetCommentInPost(commentId string, postId string) Comment {
	comments := GetByPostId(postId)
	for _, comment := range comments {
		if comment.id == commentId {
			return comment
		}
	}

	panic("comment not found")
}

func RateComment(isLike bool, postId string, commentId string) {
	comment := GetComment(commentId)
	if isLike {
		comment.likes++
	} else {
		comment.dislikes++
	}

	UpdateComment(comment, postId)
}

func UpdateComment(comment Comment, postId string) {
	ctx := storage.GetContext()
	comments := GetByPostId(postId)
	for i := 0; i < len(comments); i++ {
		if comments[i].id == comment.id {
			comments[i] = comment
		}
	}

	storage.Put(ctx, comment_prefix+postId, std.Serialize(comments))
	storage.Put(ctx, comment.id, std.Serialize(comment))
}