// Code scaffolded by goctl. Safe to edit.
// goctl 1.9.2

package file

import (
	"context"
	"time"

	"github.com/perfect-panel/server/internal/svc"
	"github.com/perfect-panel/server/internal/types"
	"github.com/perfect-panel/server/pkg/logger"
)

type FileUploadInitLogic struct {
	logger.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

// Init file upload
func NewFileUploadInitLogic(ctx context.Context, svcCtx *svc.ServiceContext) *FileUploadInitLogic {
	return &FileUploadInitLogic{
		Logger: logger.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *FileUploadInitLogic) FileUploadInit(req *types.FileUploadInitRequest) (resp *types.FileUploadInitResponse, err error) {
	u, err := currentUserFromContext(l.ctx)
	if err != nil {
		return nil, err
	}

	if err := validateInitRequest(l.svcCtx, req.BizType, req.FileName, req.ContentType, req.Size); err != nil {
		return nil, err
	}

	now := time.Now()
	fileID := buildFileID(u.Id, req.BizType, req.FileName)
	objectKey := buildObjectKey(l.svcCtx.Config.S3.Prefix, u.Id, req.BizType, fileID, req.FileName, now)
	expireSeconds := l.svcCtx.Config.S3.PresignExpireSeconds
	if expireSeconds <= 0 {
		expireSeconds = 300
	}

	presigned, err := l.svcCtx.S3Store.PresignPutObject(l.ctx, objectKey, req.ContentType, time.Duration(expireSeconds)*time.Second)
	if err != nil {
		l.Errorw("presign put object failed", logger.Field("error", err.Error()), logger.Field("user_id", u.Id))
		return nil, err
	}

	meta := &uploadMeta{
		FileID:      fileID,
		UserID:      u.Id,
		BizType:     req.BizType,
		FileName:    req.FileName,
		ContentType: req.ContentType,
		ObjectKey:   objectKey,
		Size:        req.Size,
		Sha256:      req.Sha256,
		Status:      fileUploadInitStatus,
		CreatedAt:   now.Unix(),
	}
	if err := saveUploadMeta(l.ctx, l.svcCtx, meta, 24*time.Hour); err != nil {
		return nil, err
	}

	return &types.FileUploadInitResponse{
		FileId:    fileID,
		ObjectKey: objectKey,
		UploadURL: presigned.URL,
		Method:    presigned.Method,
		Headers: map[string]string{
			"Content-Type": req.ContentType,
		},
		ExpiredAt: presigned.ExpiresAt,
	}, nil
}
