package repository

import (
	model "authservice/internal/model"
	"authservice/internal/persistance/database"
	"authservice/internal/tools"
	"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"
	"time"
)

const (
	UserCollection = "users"
)

type AuthRepository struct {
	Database *database.Database
}

func (repository *AuthRepository) CheckIfUserExists(context context.Context, email string) (*model.User, error) {
	userCollection := repository.Database.Client.Collection(UserCollection)

	filter := bson.D{
		{"email", email},
	}

	result := userCollection.FindOne(context, filter)

	if result.Err() == mongo.ErrNoDocuments {
		return nil, tools.ConvertError(codes.NotFound, "User with provided email not found", result.Err())
	}

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

	user := &model.User{}
	err := result.Decode(user)

	if err != nil {
		return nil, tools.ConvertError(codes.FailedPrecondition, "Failed to decode user", err)
	}

	return user, nil
}

func (repository *AuthRepository) UpdateUser(context context.Context, user *model.User, key string) (*model.User, error) {
	userCollection := repository.Database.Client.Collection(UserCollection)

	filter := bson.D{{"_id", user.Id}}
	user.Key = key
	user.LastSignIn = time.Now().Unix()
	update := bson.D{{"$set", user}}
	result, err := userCollection.UpdateOne(context, filter, update)
	if err != nil {
		return nil, tools.ConvertError(codes.FailedPrecondition, "Database error", err)
	}
	if result.MatchedCount == 0 {
		return nil, tools.CreateError(codes.NotFound, "User not found in database", "User dont exists")
	}
	return user, nil
}

func (repository *AuthRepository) GetUserById(context context.Context, id primitive.ObjectID) (*model.User, error) {
	userCollection := repository.Database.Client.Collection(UserCollection)

	filter := bson.D{
		{"_id", id},
	}

	result := userCollection.FindOne(context, filter)

	if result.Err() == mongo.ErrNoDocuments {
		return nil, tools.ConvertError(codes.NotFound, "User with provided id not found", result.Err())
	}

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

	user := &model.User{}
	err := result.Decode(user)

	if err != nil {
		return nil, tools.ConvertError(codes.FailedPrecondition, "Failed to decode user", err)
	}

	return user, nil
}

func (repository *AuthRepository) CreateUser(context context.Context, email string, password string, key string) (*model.User, error) {
	userCollection := repository.Database.Client.Collection(UserCollection)

	user := model.User{
		Id:               nil,
		LastSignIn:       time.Now().Unix(),
		AccountCreatedAt: time.Now().Unix(),
		Email:            email,
		Password:         password,
		Key:              key,
	}

	result, err := userCollection.InsertOne(context, user)

	if err != nil {
		return nil, tools.ConvertError(codes.FailedPrecondition, "Failed to decode user", err)
	}

	return repository.GetUserById(context, result.InsertedID.(primitive.ObjectID))
}
