package repository

import (
	"context"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"google.golang.org/grpc/codes"
	"permissionservice/internal/model"
	"permissionservice/internal/persistance/database"
	"permissionservice/internal/tools"
)

const (
	PermissionCollection = "permissions"
)

type PermissionRepository struct {
	Database *database.Database
}

func (repository *PermissionRepository) CreateNotePermission(context context.Context, userId string, noteId string, permissions *model.Permissions) error {
	permissionCollection := repository.Database.Client.Collection(PermissionCollection)

	notePermission := &model.NotePermission{
		UserId:      userId,
		NoteId:      noteId,
		Permissions: *permissions,
	}

	_, err := permissionCollection.InsertOne(context, notePermission)
	if err != nil {
		return tools.ConvertError(codes.Internal, "Failed to insert note permissions", err)
	}
	return nil
}

func (repository *PermissionRepository) GetAllNotePermissions(context context.Context, userId string) ([]*model.NotePermission, error) {
	permissionCollection := repository.Database.Client.Collection(PermissionCollection)
	filter := bson.D{
		{"userId", userId},
	}
	cursor, err := permissionCollection.Find(context, filter)
	if err != nil {
		return nil, tools.ConvertError(codes.Internal, "Database error", err)
	}

	if cursor == nil {
		return nil, tools.CreateError(codes.NotFound, "No note correspond to provided id", "Not found")
	}
	var result []*model.NotePermission
	for cursor.Next(context) {
		notePermission := &model.NotePermission{}
		err := cursor.Decode(notePermission)
		if err != nil {
			return nil, tools.ConvertError(codes.Internal, "Can`t decode notePermission", err)
		}
		result = append(result, notePermission)
	}
	return result, nil
}

func (repository *PermissionRepository) DeleteNotePermissions(context context.Context, permissionId *primitive.ObjectID) error {
	permissionCollection := repository.Database.Client.Collection(PermissionCollection)
	filter := bson.M{"_id": permissionId}
	result, err := permissionCollection.DeleteOne(context, filter)
	if err != nil {
		return tools.ConvertError(codes.Internal, "Error on note delete", err)
	}

	if result.DeletedCount == 0 {
		return tools.CreateError(codes.NotFound, "Note permission with provided id not found", "Note permission not found")
	}
	return nil
}

func (repository *PermissionRepository) CheckIfUserHavePermissions(context context.Context, userId string, noteId string, permissions *model.Permissions) (*model.NotePermission, error) {
	permissionCollection := repository.Database.Client.Collection(PermissionCollection)
	filter := bson.D{
		{"userId", userId},
		{"noteId", noteId},
	}
	result := permissionCollection.FindOne(context, filter)
	if result.Err() == mongo.ErrNoDocuments {
		return nil, tools.ConvertError(codes.NotFound, "User dont have any permissions ot note dont exists", result.Err())
	}

	if result.Err() != nil {
		return nil, tools.ConvertError(codes.Internal, "Database error", result.Err())
	}

	notePermissions := &model.NotePermission{}
	err := result.Decode(notePermissions)
	if err != nil {
		return nil, tools.ConvertError(codes.Internal, "Failed to decode note permissions", err)
	}

	if permissions.Read && !notePermissions.Permissions.Read {
		return nil, tools.CreateError(codes.PermissionDenied, "User dont have read permissions for note", "Missing read permissions")
	}
	if permissions.Write && !notePermissions.Permissions.Write {
		return nil, tools.CreateError(codes.PermissionDenied, "User dont have write permissions for note", "Missing write permissions")
	}
	if permissions.Delete && !notePermissions.Permissions.Delete {
		return nil, tools.CreateError(codes.PermissionDenied, "User dont have delete permissions for note", "Missing delete permissions")
	}
	if permissions.Share && !notePermissions.Permissions.Share {
		return nil, tools.CreateError(codes.PermissionDenied, "User dont have share permissions for note", "Missing share permissions")
	}
	if permissions.Owner && !notePermissions.Permissions.Owner {
		return nil, tools.CreateError(codes.PermissionDenied, "User dont have owner permissions for note", "Missing owner permissions")
	}
	return notePermissions, nil
}
