package repository

import (
	"context"
	"log"
	"time"

	"pki-manager/internal/models"

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

type MongoRepository struct {
	db *mongo.Database
}

func NewMongoRepository(db *mongo.Database) *MongoRepository {
	return &MongoRepository{db: db}
}

func (r *MongoRepository) CreateCA(ctx context.Context, ca *models.CA) error {
	ca.CreatedAt = time.Now()
	ca.UpdatedAt = time.Now()

	_, err := r.db.Collection("cas").InsertOne(ctx, ca)
	return err
}

func (r *MongoRepository) GetCA(ctx context.Context, id string) (*models.CA, error) {
	var ca models.CA
	err := r.db.Collection("cas").FindOne(ctx, bson.M{"_id": id}).Decode(&ca)
	if err != nil {
		return nil, err
	}
	return &ca, nil
}

func (r *MongoRepository) GetAllCAs(ctx context.Context) ([]*models.CA, error) {
	var cas []*models.CA
	cursor, err := r.db.Collection("cas").Find(ctx, bson.M{})
	if err != nil {
		// Retourner un tableau vide au lieu d'une erreur
		return []*models.CA{}, nil
	}
	defer cursor.Close(ctx)

	for cursor.Next(ctx) {
		var ca models.CA
		if err := cursor.Decode(&ca); err != nil {
			continue // Ignorer les erreurs de décodage
		}
		cas = append(cas, &ca)
	}

	return cas, nil
}

func (r *MongoRepository) UpdateCA(ctx context.Context, id string, updates map[string]interface{}) error {
	updates["updated_at"] = time.Now()
	_, err := r.db.Collection("cas").UpdateOne(
		ctx,
		bson.M{"_id": id},
		bson.M{"$set": updates},
	)
	return err
}

func (r *MongoRepository) DeleteCA(ctx context.Context, id string) error {
	_, err := r.db.Collection("cas").DeleteOne(ctx, bson.M{"_id": id})
	return err
}

// SubCA methods
func (r *MongoRepository) CreateSubCA(ctx context.Context, subca *models.SubCA) error {
	subca.CreatedAt = time.Now()
	subca.UpdatedAt = time.Now()

	_, err := r.db.Collection("subcas").InsertOne(ctx, subca)
	return err
}

func (r *MongoRepository) GetSubCA(ctx context.Context, id string) (*models.SubCA, error) {
	var subca models.SubCA
	err := r.db.Collection("subcas").FindOne(ctx, bson.M{"_id": id}).Decode(&subca)
	if err != nil {
		return nil, err
	}
	return &subca, nil
}

func (r *MongoRepository) GetSubCAsByParent(ctx context.Context, parentCAID string) ([]*models.SubCA, error) {
	var subcas []*models.SubCA
	cursor, err := r.db.Collection("subcas").Find(ctx, bson.M{"parent_ca_id": parentCAID})
	if err != nil {
		return nil, err
	}
	defer cursor.Close(ctx)

	for cursor.Next(ctx) {
		var subca models.SubCA
		if err := cursor.Decode(&subca); err != nil {
			log.Println("Error decoding SubCA:", err)
			continue
		}
		subcas = append(subcas, &subca)
	}
	return subcas, nil
}

func (r *MongoRepository) GetAllSubCAs(ctx context.Context) ([]*models.SubCA, error) {
	var subcas []*models.SubCA
	cursor, err := r.db.Collection("subcas").Find(ctx, bson.M{})
	if err != nil {
		// Retourner un tableau vide au lieu d'une erreur
		return []*models.SubCA{}, nil
	}
	defer cursor.Close(ctx)

	for cursor.Next(ctx) {
		var subca models.SubCA
		if err := cursor.Decode(&subca); err != nil {
			continue // Ignorer les erreurs de décodage
		}
		subcas = append(subcas, &subca)
	}

	return subcas, nil
}

func (r *MongoRepository) UpdateSubCA(ctx context.Context, id string, updates map[string]interface{}) error {
	updates["updated_at"] = time.Now()
	_, err := r.db.Collection("subcas").UpdateOne(
		ctx,
		bson.M{"_id": id},
		bson.M{"$set": updates},
	)
	return err
}

func (r *MongoRepository) DeleteSubCA(ctx context.Context, id string) error {
	_, err := r.db.Collection("subcas").DeleteOne(ctx, bson.M{"_id": id})
	return err
}

// Certificate methods
func (r *MongoRepository) CreateCertificate(ctx context.Context, cert *models.Certificate) error {
	cert.CreatedAt = time.Now()

	_, err := r.db.Collection("certificates").InsertOne(ctx, cert)
	return err
}

func (r *MongoRepository) GetCertificate(ctx context.Context, id string) (*models.Certificate, error) {
	var cert models.Certificate
	err := r.db.Collection("certificates").FindOne(ctx, bson.M{"_id": id}).Decode(&cert)
	if err != nil {
		return nil, err
	}
	return &cert, nil
}

func (r *MongoRepository) GetCertificatesByIssuer(ctx context.Context, issuerCAID string) ([]*models.Certificate, error) {
	var certs []*models.Certificate
	cursor, err := r.db.Collection("certificates").Find(ctx, bson.M{"issuer_ca_id": issuerCAID})
	if err != nil {
		return nil, err
	}
	defer cursor.Close(ctx)

	for cursor.Next(ctx) {
		var cert models.Certificate
		if err := cursor.Decode(&cert); err != nil {
			log.Println("Error decoding certificate:", err)
			continue
		}
		certs = append(certs, &cert)
	}
	return certs, nil
}

func (r *MongoRepository) GetAllCertificates(ctx context.Context) ([]*models.Certificate, error) {
	var certs []*models.Certificate
	cursor, err := r.db.Collection("certificates").Find(ctx, bson.M{})
	if err != nil {
		// Retourner un tableau vide au lieu d'une erreur
		return []*models.Certificate{}, nil
	}
	defer cursor.Close(ctx)

	for cursor.Next(ctx) {
		var cert models.Certificate
		if err := cursor.Decode(&cert); err != nil {
			continue // Ignorer les erreurs de décodage
		}
		certs = append(certs, &cert)
	}

	return certs, nil
}

func (r *MongoRepository) UpdateCertificate(ctx context.Context, id string, updates map[string]interface{}) error {
	_, err := r.db.Collection("certificates").UpdateOne(
		ctx,
		bson.M{"_id": id},
		bson.M{"$set": updates},
	)
	return err
}

func (r *MongoRepository) DeleteCertificate(ctx context.Context, id string) error {
	_, err := r.db.Collection("certificates").DeleteOne(ctx, bson.M{"_id": id})
	return err
}

func (r *MongoRepository) RevokeCertificate(ctx context.Context, id string, reason string) error {
	updates := bson.M{
		"revoked":        true,
		"revoked_at":     time.Now(),
		"revoked_reason": reason,
	}

	_, err := r.db.Collection("certificates").UpdateOne(
		ctx,
		bson.M{"_id": id},
		bson.M{"$set": updates},
	)
	return err
}
