package mongos

import (
	"context"
	"errors"
	"fmt"
	"github.com/Pena-Co-Ltd/amocrm_templategen_back/dal/model"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"go.uber.org/zap"
	"time"
)

type Template struct {
	coll   *mongo.Collection
	logger *zap.Logger
}

func InitTemplate(db *mongo.Database, logger *zap.Logger) *Template {
	return &Template{coll: db.Collection("template"), logger: logger}
}

func (d *Template) Insert(ctx context.Context, record *model.Template) (string, error) {
	now := time.Now()
	record.CreatedAt = now
	record.UpdatedAt = now
	record.IsDeleted = false

	if record.UserID == "" {
		err := errors.New("got empty user id")
		d.logger.Error("ErrorDeleteTemplate", zap.Error(err))
		return "", err
	}

	found, err := d.GetByNameAndUserID(ctx, record.Name, record.UserID)
	if err != nil {
		d.logger.Error("ErrorInsertTemplate", zap.Error(err))
		return "", err
	}

	if found != nil {
		err = errors.New("template with this name already exists")
		d.logger.Error("ErrorInsertTemplate", zap.Error(err))
		return "", err
	}

	result, err := d.coll.InsertOne(ctx, record)

	if err != nil {
		d.logger.Error("ErrorInsertTemplate", zap.Error(err))
		return "", err
	}

	return result.InsertedID.(primitive.ObjectID).Hex(), nil
}

func (d *Template) GetByID(ctx context.Context, id string) (*model.Template, error) {
	objID, err := primitive.ObjectIDFromHex(id)

	if err != nil {
		d.logger.Error("ErrorGetTemplate", zap.Error(err))
		return nil, err
	}

	filter := bson.M{"_id": objID, "is_deleted": false}

	var result model.Template

	err = d.coll.FindOne(ctx, filter).Decode(&result)

	if err == mongo.ErrNoDocuments {
		return nil, nil
	} else {
		if err != nil {
			d.logger.Error("ErrorGetTemplate", zap.Error(err))
			return nil, err
		}
	}

	d.logger.Info("InfoGetTemplate", zap.String("id", result.ID))

	return &result, nil
}

func (d *Template) GetByLeadId(ctx context.Context, id string) (*model.Template, error) {
	filter := bson.M{"lead_id": id, "is_deleted": false}

	var result model.Template

	err := d.coll.FindOne(ctx, filter).Decode(&result)

	if err == mongo.ErrNoDocuments {
		return nil, nil
	} else {
		if err != nil {
			d.logger.Error("ErrorGetTemplate", zap.Error(err))
			return nil, err
		}
	}

	d.logger.Info("InfoGetTemplate", zap.String("id", result.ID))

	return &result, nil
}

func (d *Template) GetByNameAndUserID(ctx context.Context, name, userID string) (*model.Template, error) {
	filter := bson.M{"name": name, "user_id": userID, "is_deleted": false}

	fmt.Println("-----------------------------------")
	fmt.Println(filter)

	var result model.Template
	err := d.coll.FindOne(ctx, filter).Decode(&result)

	if err == mongo.ErrNoDocuments {
		return nil, nil
	} else {
		if err != nil {
			d.logger.Error("ErrorGetTemplate", zap.Error(err))
			return nil, err
		}
	}

	fmt.Println("RESUKLT", result)

	d.logger.Info("InfoGetTemplate", zap.String("id", result.ID))

	return &result, nil
}

func (d *Template) GetByFilenameAndUserID(ctx context.Context, name, userID string) (*model.Template, error) {
	filter := bson.M{"filename": name, "user_id": userID, "is_deleted": false}

	var result model.Template

	err := d.coll.FindOne(ctx, filter).Decode(&result)

	if err == mongo.ErrNoDocuments {
		return nil, nil
	} else {
		if err != nil {
			d.logger.Error("ErrorGetTemplate", zap.Error(err))
			return nil, err
		}
	}

	d.logger.Info("InfoGetTemplate", zap.String("id", result.ID))

	return &result, nil
}

func (d *Template) GetListByUserID(ctx context.Context, userID string) ([]model.Template, error) {
	filter := bson.M{"user_id": userID, "is_deleted": false}

	var result []model.Template

	cursor, err := d.coll.Find(ctx, filter)

	if err == mongo.ErrNoDocuments {
		return nil, nil
	} else {
		if err != nil {
			d.logger.Error("ErrorGetTemplate", zap.Error(err))
			return nil, err
		}
	}

	err = cursor.All(ctx, &result)
	if err == mongo.ErrNoDocuments {
		return nil, nil
	} else {
		if err != nil {
			d.logger.Error("ErrorGetTemplate", zap.Error(err))
			return nil, err
		}
	}

	return result, nil
}

func (d *Template) GetListByUserIDAndStorage(ctx context.Context, userID, storage string) ([]model.Template, error) {
	filter := bson.M{"user_id": userID, "storage": storage, "is_deleted": false}

	var result []model.Template

	cursor, err := d.coll.Find(ctx, filter)

	if err == mongo.ErrNoDocuments {
		return nil, nil
	} else {
		if err != nil {
			d.logger.Error("ErrorGetTemplate", zap.Error(err))
			return nil, err
		}
	}

	err = cursor.All(ctx, &result)
	if err == mongo.ErrNoDocuments {
		return nil, nil
	} else {
		if err != nil {
			d.logger.Error("ErrorGetTemplate", zap.Error(err))
			return nil, err
		}
	}

	return result, nil
}

func (d *Template) UpdateByID(ctx context.Context, record *model.Template) error {
	if record.ID == "" {
		err := errors.New("got empty id")
		d.logger.Error("ErrorUpdateTemplate", zap.Error(err))
		return err
	}

	objID, err := primitive.ObjectIDFromHex(record.ID)

	if err != nil {
		d.logger.Error("ErrorUpdateTemplate", zap.Error(err))
		return err
	}

	filter := bson.M{"_id": objID, "is_deleted": false}

	update := bson.M{"updated_at": time.Now()}

	if record.Name != "" {
		update["name"] = record.Name
	}

	if record.Filename != "" {
		update["filename"] = record.Filename
	}

	if record.LeadId != "" {
		update["lead_id"] = record.LeadId
	}

	if record.LeadId != "" {
		update["storage"] = record.StorageID
	}

	if record.FileID != "" {
		update["file_id"] = record.FileID
	}

	res, err := d.coll.UpdateOne(ctx, filter, bson.D{{"$set", update}})

	fmt.Println(update)
	fmt.Println(res)

	if err != nil {
		d.logger.Error("ErrorUpdateTemplate", zap.Error(err))
		return err
	}

	return nil
}

func (d *Template) UpdateByLeadID(ctx context.Context, record *model.Template) error {
	if record.LeadId == "" {
		err := errors.New("got empty id")
		d.logger.Error("ErrorUpdateTemplate", zap.Error(err))
		return err
	}

	filter := bson.M{"lead_id": record.LeadId, "is_deleted": false}

	update := bson.M{"updated_at": time.Now()}

	if record.Name != "" {
		update["name"] = record.Name
	}

	if record.Filename != "" {
		update["filename"] = record.Filename
	}

	if record.LeadId != "" {
		update["lead_id"] = record.LeadId
	}

	if record.LeadId != "" {
		update["storage"] = record.StorageID
	}

	if record.FileID != "" {
		update["file_id"] = record.FileID
	}

	_, err := d.coll.UpdateOne(ctx, filter, bson.D{{"$set", update}})

	if err != nil {
		d.logger.Error("ErrorUpdateTemplate", zap.Error(err))
		return err
	}

	return nil
}

func (d *Template) UpdateByNameAndUserID(ctx context.Context, record *model.Template) error {
	if record.Name == "" || record.UserID == "" {
		err := errors.New("got empty user id or name")
		d.logger.Error("ErrorUpdateTemplate", zap.Error(err))
		return err
	}

	filter := bson.M{"name": record.Name, "user_id": record.UserID, "is_deleted": false}

	update := bson.M{"updated_at": time.Now()}

	if record.Filename != "" {
		update["filename"] = record.Filename
	}

	_, err := d.coll.UpdateOne(ctx, filter, update)

	if err != nil {
		d.logger.Error("ErrorUpdateTemplate", zap.Error(err))
		return err
	}

	return nil
}

func (d *Template) DeleteByID(ctx context.Context, id string) error {
	if id == "" {
		err := errors.New("got empty id")
		d.logger.Error("ErrorDeleteTemplate", zap.Error(err))
		return err
	}

	objID, err := primitive.ObjectIDFromHex(id)

	if err != nil {
		d.logger.Error("ErrorDeleteTemplate", zap.Error(err))
		return err
	}

	filter := bson.M{"_id": objID, "is_deleted": false}

	update := bson.M{"updated_at": time.Now(), "is_deleted": true}

	_, err = d.coll.UpdateOne(ctx, filter, bson.D{{"$set", update}})
	if err != nil {
		d.logger.Error("ErrorDeleteTemplate", zap.Error(err))
		return err
	}

	return nil
}

func (d *Template) DeleteByNameAndUserID(ctx context.Context, name, userID string) error {
	if name == "" || userID == "" {
		err := errors.New("got empty user id or name")
		d.logger.Error("ErrorUpdateTemplate", zap.Error(err))
		return err
	}

	filter := bson.M{"name": name, "user_id": userID, "is_deleted": false}

	update := bson.M{"updated_at": time.Now(), "is_deleted": true}

	_, err := d.coll.UpdateOne(ctx, filter, bson.D{{"$set", update}})
	if err != nil {
		d.logger.Error("ErrorDeleteTemplate", zap.Error(err))
		return err
	}

	return nil
}
