package database

import (
	"context"
	"errors"

	"git.anthrove.art/Anthrove/otter-space-sdk/v6/internal/utils"
	otterError "git.anthrove.art/Anthrove/otter-space-sdk/v6/pkg/error"
	"git.anthrove.art/Anthrove/otter-space-sdk/v6/pkg/models"
	log "github.com/sirupsen/logrus"
	"go.opentelemetry.io/otel/attribute"
	"gorm.io/gorm"
)

func CreatePostReport(ctx context.Context, postReport models.PostReport) (models.PostReport, error) {
	ctx, span, localLogger := utils.SetupTracing(ctx, tracer, "CreatePostReport")
	defer span.End()

	localLogger = localLogger.WithFields(log.Fields{
		"post_report_id": postReport.ID,
	})

	span.SetAttributes(
		attribute.String("post_report_id", string(postReport.ID)),
	)

	utils.HandleEvent(span, localLogger, "Starting postReport creation")

	if client == nil {
		return models.PostReport{}, utils.HandleError(ctx, span, localLogger, &otterError.Database{Reason: otterError.DatabaseIsNotConnected})
	}

	result := client.WithContext(ctx).Create(&postReport)
	if result.Error != nil {
		if errors.Is(result.Error, gorm.ErrDuplicatedKey) {
			return models.PostReport{}, utils.HandleError(ctx, span, localLogger, &otterError.Database{Reason: otterError.DuplicateKey})
		}
		return models.PostReport{}, utils.HandleError(ctx, span, localLogger, result.Error)
	}

	utils.HandleEvent(span, localLogger, "Post createdReport successfully")
	return postReport, nil
}

func GetPostReportByID(ctx context.Context, id models.PostReportID) (models.PostReport, error) {
	ctx, span, localLogger := utils.SetupTracing(ctx, tracer, "GetPostReportByID")
	defer span.End()

	localLogger = localLogger.WithFields(log.Fields{
		"post_report_id": id,
	})

	span.SetAttributes(
		attribute.String("post_report_id", string(id)),
	)

	utils.HandleEvent(span, localLogger, "Starting get postReport by ID")

	var postReport models.PostReport

	if client == nil {
		return models.PostReport{}, utils.HandleError(ctx, span, localLogger, &otterError.Database{Reason: otterError.DatabaseIsNotConnected})
	}

	if len(id) == 0 {
		return models.PostReport{}, utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.PostReportIDIsEmpty})
	}

	if len(id) != 25 {
		return models.PostReport{}, utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.PostReportIDIsWrongLength})
	}

	result := client.WithContext(ctx).First(&postReport, "id = ?", id)
	if result.Error != nil {
		if errors.Is(result.Error, gorm.ErrRecordNotFound) {
			return models.PostReport{}, utils.HandleError(ctx, span, localLogger, &otterError.Database{Reason: otterError.NoDataFound})
		}
		return models.PostReport{}, utils.HandleError(ctx, span, localLogger, result.Error)
	}

	utils.HandleEvent(span, localLogger, "PostReport retrieved successfully")
	return postReport, nil
}

// UpdatePostReport updates the PostReport information in the database.
// Only a few parameter can be updated:
//   - AuditBy
//   - AuditDescription
//   - ReportType
//   - ReportState
func UpdatePostReport(ctx context.Context, postReport models.PostReport) error {
	ctx, span, localLogger := utils.SetupTracing(ctx, tracer, "UpdatePostReport")
	defer span.End()

	localLogger = localLogger.WithFields(log.Fields{
		"post_report_id": postReport.ID,
	})

	span.SetAttributes(
		attribute.String("post_report_id", string(postReport.ID)),
	)

	utils.HandleEvent(span, localLogger, "Starting postReport update")

	if client == nil {
		return utils.HandleError(ctx, span, localLogger, &otterError.Database{Reason: otterError.DatabaseIsNotConnected})
	}

	if len(postReport.ID) == 0 {
		return utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.PostIDIsEmpty})
	}

	updatePost := models.PostReport{
		BaseModel: models.BaseModel[models.PostReportID]{
			ID: postReport.ID,
		},
		AuditBy:          postReport.AuditBy,
		AuditDescription: postReport.AuditDescription,
		ReportType:       postReport.ReportType,
		ReportState:      postReport.ReportState,
	}

	result := client.WithContext(ctx).Model(&updatePost).Updates(updatePost)
	if result.Error != nil {
		if errors.Is(result.Error, gorm.ErrRecordNotFound) {
			return utils.HandleError(ctx, span, localLogger, &otterError.Database{Reason: otterError.NoDataFound})
		}
		return utils.HandleError(ctx, span, localLogger, result.Error)
	}

	utils.HandleEvent(span, localLogger, "PostReport updated successfully")
	return nil
}

func DeletePostReport(ctx context.Context, id models.PostReportID) error {
	ctx, span, localLogger := utils.SetupTracing(ctx, tracer, "DeletePostReport")
	defer span.End()

	localLogger = localLogger.WithFields(log.Fields{
		"post_report_id": id,
	})

	span.SetAttributes(
		attribute.String("post_report_id", string(id)),
	)

	utils.HandleEvent(span, localLogger, "Starting delete postReport")

	var postReport models.PostReport

	if client == nil {
		return utils.HandleError(ctx, span, localLogger, &otterError.Database{Reason: otterError.DatabaseIsNotConnected})
	}

	if len(id) == 0 {
		return utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.PostReportIDIsEmpty})
	}

	if len(id) != 25 {
		return utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.PostReportIDIsWrongLength})
	}

	result := client.WithContext(ctx).Delete(&postReport, "id = ?", id)
	if result.Error != nil {
		if errors.Is(result.Error, gorm.ErrRecordNotFound) {
			return utils.HandleError(ctx, span, localLogger, &otterError.Database{Reason: otterError.NoDataFound})
		}
		return utils.HandleError(ctx, span, localLogger, result.Error)
	}

	utils.HandleEvent(span, localLogger, "PostReport deleted successfully")
	return nil
}