// Package mongodb provides MongoDB client functionality for the operator
package mongodb

import (
	"context"
	"fmt"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	ctrl "sigs.k8s.io/controller-runtime"
)

const (
	DatabaseName   = "container-mom"
	CollectionName = "deployments"
)

func (c *Client) GetDeployment(ctx context.Context, id string) (*MongoDeployment, error) {
	collection := c.client.Database(DatabaseName).Collection(CollectionName)

	var deployment MongoDeployment
	err := collection.FindOne(ctx, bson.M{"_id": id}).Decode(&deployment)
	if err != nil {
		if err == mongo.ErrNoDocuments {
			return nil, fmt.Errorf("deployment not found")
		}
		return nil, err
	}

	return &deployment, nil
}

func (c *Client) ListDeployments(ctx context.Context) ([]MongoDeployment, error) {
	collection := c.client.Database(DatabaseName).Collection(CollectionName)

	cursor, err := collection.Find(ctx, bson.M{})
	if err != nil {
		return nil, fmt.Errorf("failed to query deployments: %w", err)
	}
	defer cursor.Close(ctx)

	var deployments []MongoDeployment
	if err := cursor.All(ctx, &deployments); err != nil {
		return nil, fmt.Errorf("failed to decode deployments: %w", err)
	}

	ctrl.Log.Info("listed deployments from MongoDB",
		"count", len(deployments),
		"collection", collection.Name(),
	)

	return deployments, nil
}

func (c *Client) CreateDeployment(ctx context.Context, deployment *MongoDeployment) error {
	collection := c.client.Database(DatabaseName).Collection(CollectionName)

	_, err := collection.InsertOne(ctx, deployment)
	return err
}

func (c *Client) UpdateDeployment(ctx context.Context, deployment *MongoDeployment) error {
	collection := c.client.Database(DatabaseName).Collection(CollectionName)

	result, err := collection.ReplaceOne(ctx, bson.M{"_id": deployment.ID}, deployment)
	if err != nil {
		return err
	}
	if result.MatchedCount == 0 {
		return fmt.Errorf("deployment not found")
	}
	return nil
}

func (c *Client) DeleteDeployment(ctx context.Context, id string) error {
	collection := c.client.Database(DatabaseName).Collection(CollectionName)

	result, err := collection.DeleteOne(ctx, bson.M{"_id": id})
	if err != nil {
		return err
	}
	if result.DeletedCount == 0 {
		return fmt.Errorf("deployment not found")
	}
	return nil
}

func (c *Client) GetClient() *mongo.Client {
	return c.client
}

func (c *Client) Disconnect(ctx context.Context) error {
	return c.client.Disconnect(ctx)
}

func (c *Client) Database(name string) *mongo.Database {
	return c.client.Database(name)
}
