package repository

import (
	"context"

	"haixun-backend/internal/library/clock"
	app "haixun-backend/internal/library/errors"
	"haixun-backend/internal/library/errors/code"
	"haixun-backend/internal/model/permission/domain/entity"
	domrepo "haixun-backend/internal/model/permission/domain/repository"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type mongoPermissionRepository struct {
	collection *mongo.Collection
}

func NewMongoPermissionRepository(db *mongo.Database) domrepo.PermissionRepository {
	if db == nil {
		return &mongoPermissionRepository{}
	}
	return &mongoPermissionRepository{collection: db.Collection(entity.PermissionCollectionName)}
}

func (r *mongoPermissionRepository) EnsureIndexes(ctx context.Context) error {
	if r.collection == nil {
		return nil
	}
	_, err := r.collection.Indexes().CreateMany(ctx, []mongo.IndexModel{
		{Keys: bson.D{{Key: "name", Value: 1}}, Options: options.Index().SetUnique(true)},
		{Keys: bson.D{{Key: "parent", Value: 1}}},
		{Keys: bson.D{{Key: "status", Value: 1}}},
		{Keys: bson.D{{Key: "type", Value: 1}}},
	})
	return err
}

func (r *mongoPermissionRepository) UpsertByName(ctx context.Context, permission *entity.Permission) error {
	if r.collection == nil {
		return app.For(code.Permission).DBUnavailable("Mongo is not configured")
	}
	now := clock.NowUnixNano()
	if permission.Status == "" {
		permission.Status = entity.StatusOpen
	}
	if permission.Type == "" {
		permission.Type = entity.TypeBackendUser
	}
	_, err := r.collection.UpdateOne(
		ctx,
		bson.M{"name": permission.Name},
		bson.M{
			"$set": bson.M{
				"parent":       permission.Parent,
				"name":         permission.Name,
				"http_methods": permission.HTTPMethods,
				"http_path":    permission.HTTPPath,
				"status":       permission.Status,
				"type":         permission.Type,
				"update_at":    now,
			},
			"$setOnInsert": bson.M{"create_at": now},
		},
		options.Update().SetUpsert(true),
	)
	return err
}

func (r *mongoPermissionRepository) List(ctx context.Context, filter domrepo.PermissionFilter) ([]*entity.Permission, error) {
	if r.collection == nil {
		return nil, app.For(code.Permission).DBUnavailable("Mongo is not configured")
	}
	query := bson.M{}
	if filter.Status != "" {
		query["status"] = filter.Status
	}
	if filter.Type != "" {
		query["type"] = filter.Type
	}
	cursor, err := r.collection.Find(ctx, query, options.Find().SetSort(bson.D{{Key: "name", Value: 1}}))
	if err != nil {
		return nil, err
	}
	defer cursor.Close(ctx)
	var out []*entity.Permission
	if err := cursor.All(ctx, &out); err != nil {
		return nil, err
	}
	return out, nil
}

func (r *mongoPermissionRepository) ListByIDs(ctx context.Context, ids []string) ([]*entity.Permission, error) {
	if r.collection == nil {
		return nil, app.For(code.Permission).DBUnavailable("Mongo is not configured")
	}
	if len(ids) == 0 {
		return nil, nil
	}
	cursor, err := r.collection.Find(ctx, bson.M{"_id": bson.M{"$in": objectIDs(ids)}})
	if err != nil {
		return nil, err
	}
	defer cursor.Close(ctx)
	var out []*entity.Permission
	if err := cursor.All(ctx, &out); err != nil {
		return nil, err
	}
	return out, nil
}
