package utils

import (
	"errors"
	"strings"

	"gitlab.com/mbugroup/lti-api.git/internal/common/validation"
	"gitlab.com/mbugroup/lti-api.git/internal/response"

	"github.com/gofiber/fiber/v2"
	"github.com/jackc/pgconn"
	pgconnv5 "github.com/jackc/pgx/v5/pgconn"
)

func ErrorHandler(c *fiber.Ctx, err error) error {
	if message, errorsMap := validation.CustomErrorMessages(err); len(errorsMap) > 0 {
		return response.Error(c, fiber.StatusBadRequest, message, nil)
	}

	if statusCode, message := mapPgError(err); statusCode != 0 {
		return response.Error(c, statusCode, message, nil)
	}

	var fiberErr *fiber.Error
	if errors.As(err, &fiberErr) {
		return response.Error(c, fiberErr.Code, fiberErr.Message, nil)
	}

	return response.Error(c, fiber.StatusInternalServerError, "Internal Server Error", nil)
}

func NotFoundHandler(c *fiber.Ctx) error {
	return response.Error(c, fiber.StatusNotFound, "Endpoint Not Found", nil)
}

func mapPgError(err error) (int, string) {
	code, message := getPgErrorDetails(err)
	if code == "" {
		return 0, ""
	}

	switch code {
	case "23503":
		return fiber.StatusConflict, "Data tidak bisa dihapus karena masih digunakan oleh data lain."
	case "P0001":
		if strings.HasPrefix(message, "Cannot soft delete") {
			return fiber.StatusConflict, "Data tidak bisa dihapus karena masih digunakan oleh data lain."
		}
	}

	return 0, ""
}

func getPgErrorDetails(err error) (string, string) {
	var pgErr *pgconn.PgError
	if errors.As(err, &pgErr) {
		return pgErr.Code, pgErr.Message
	}

	var pgErrV5 *pgconnv5.PgError
	if errors.As(err, &pgErrV5) {
		return pgErrV5.Code, pgErrV5.Message
	}

	return "", ""
}

func BadRequest(msg string) error {
	return fiber.NewError(fiber.StatusBadRequest, msg)
}

func NotFound(msg string) error {
	return fiber.NewError(fiber.StatusNotFound, msg)
}

func Internal(msg string) error {
	return fiber.NewError(fiber.StatusInternalServerError, msg)
}
