package service

import (
	"verification-platform-backend/internal/database"
	"verification-platform-backend/internal/model"

	"github.com/gin-gonic/gin"
)

type LogService struct{}

type LogParams struct {
	UserID        *uint
	ApplicationID *uint
	AppUserID     *uint
	LogType       string
	Action        string
	Resource      string
	ResourceID    *uint
	Details       string
	IPAddress     string
	UserAgent     string
	DeviceID      string
	Status        string
	Level         string
	ErrorMessage  string
	StackTrace    string
}

func NewLogService() *LogService {
	return &LogService{}
}

func (s *LogService) CreateLog(params LogParams) error {
	log := model.Log{
		UserID:        params.UserID,
		ApplicationID: params.ApplicationID,
		AppUserID:     params.AppUserID,
		LogType:       params.LogType,
		Action:        params.Action,
		Resource:      params.Resource,
		ResourceID:    params.ResourceID,
		Details:       params.Details,
		IPAddress:     params.IPAddress,
		UserAgent:     params.UserAgent,
		DeviceID:      params.DeviceID,
		Status:        params.Status,
		Level:         params.Level,
		ErrorMessage:  params.ErrorMessage,
		StackTrace:    params.StackTrace,
	}

	if log.LogType == "" {
		log.LogType = "operation"
	}
	if log.Status == "" {
		log.Status = "success"
	}
	if log.Level == "" {
		log.Level = "info"
	}

	return database.DB.Create(&log).Error
}

func (s *LogService) CreateLogFromContext(c *gin.Context, params LogParams) error {
	params.IPAddress = c.ClientIP()
	params.UserAgent = c.GetHeader("User-Agent")

	if userID, exists := c.Get("user_id"); exists && params.UserID == nil {
		if uid, ok := userID.(uint); ok {
			params.UserID = &uid
		}
	}

	return s.CreateLog(params)
}

func (s *LogService) LogOperation(c *gin.Context, action, resource string, resourceID *uint, details string, err error) error {
	params := LogParams{
		LogType:    "operation",
		Action:     action,
		Resource:   resource,
		ResourceID: resourceID,
		Details:    details,
	}

	if err != nil {
		params.Status = "failed"
		params.Level = "error"
		params.ErrorMessage = err.Error()
	}

	return s.CreateLogFromContext(c, params)
}

func (s *LogService) LogOperationWithApp(c *gin.Context, applicationID *uint, action, resource string, resourceID *uint, details string, err error) error {
	params := LogParams{
		LogType:       "operation",
		ApplicationID: applicationID,
		Action:        action,
		Resource:      resource,
		ResourceID:    resourceID,
		Details:       details,
	}

	if err != nil {
		params.Status = "failed"
		params.Level = "error"
		params.ErrorMessage = err.Error()
	}

	return s.CreateLogFromContext(c, params)
}

func (s *LogService) LogVerification(c *gin.Context, applicationID *uint, appUserID *uint, action, details string, deviceID string, err error) error {
	params := LogParams{
		LogType:       "verification",
		ApplicationID: applicationID,
		AppUserID:     appUserID,
		Action:        action,
		Resource:      "verification",
		Details:       details,
		DeviceID:      deviceID,
	}

	if err != nil {
		params.Status = "failed"
		params.Level = "warning"
		params.ErrorMessage = err.Error()
	}

	return s.CreateLogFromContext(c, params)
}

func (s *LogService) LogException(c *gin.Context, action, errorMessage, stackTrace string) error {
	params := LogParams{
		LogType:      "exception",
		Action:       action,
		Resource:     "system",
		Status:       "failed",
		Level:        "error",
		ErrorMessage: errorMessage,
		StackTrace:   stackTrace,
	}

	return s.CreateLogFromContext(c, params)
}

var logService = NewLogService()

func CreateLog(params LogParams) error {
	return logService.CreateLog(params)
}

func CreateLogFromContext(c *gin.Context, params LogParams) error {
	return logService.CreateLogFromContext(c, params)
}

func LogOperation(c *gin.Context, action, resource string, resourceID *uint, details string, err error) error {
	return logService.LogOperation(c, action, resource, resourceID, details, err)
}

func LogOperationWithApp(c *gin.Context, applicationID *uint, action, resource string, resourceID *uint, details string, err error) error {
	return logService.LogOperationWithApp(c, applicationID, action, resource, resourceID, details, err)
}

func LogVerification(c *gin.Context, applicationID *uint, appUserID *uint, action, details string, DeviceFingerprint string, err error) error {
	return logService.LogVerification(c, applicationID, appUserID, action, details, DeviceFingerprint, err)
}

func LogException(c *gin.Context, action, errorMessage, stackTrace string) error {
	return logService.LogException(c, action, errorMessage, stackTrace)
}
