package smtp

import (
	"context"
	"encoding/json"
	"fmt"
	"io"

	"github.com/ultisuite/ulti-backend/internal/mail/storage"
)

// SendAttachment is a MIME body part ready for embedding in an outbound message.
type SendAttachment struct {
	Filename    string
	ContentType string
	ContentID   string
	IsInline    bool
	Data        []byte
}

// AttachmentLoader fetches attachment bytes referenced by outbox JSON.
type AttachmentLoader interface {
	Load(ctx context.Context, s3Key string) ([]byte, error)
}

// StorageAttachmentLoader loads attachment bytes from object storage.
type StorageAttachmentLoader struct {
	Client *storage.Client
}

func (l *StorageAttachmentLoader) Load(ctx context.Context, s3Key string) ([]byte, error) {
	if l == nil || l.Client == nil {
		return nil, fmt.Errorf("object storage not configured")
	}
	obj, err := l.Client.Get(ctx, s3Key)
	if err != nil {
		return nil, err
	}
	defer obj.Close()
	return io.ReadAll(obj)
}

type outboxAttachmentRef struct {
	ID          string `json:"id"`
	Filename    string `json:"filename"`
	ContentType string `json:"content_type"`
	Size        int64  `json:"size"`
	S3Bucket    string `json:"s3_bucket"`
	S3Key       string `json:"s3_key"`
	ContentID   string `json:"content_id,omitempty"`
	IsInline    bool   `json:"is_inline"`
}

func parseOutboxAttachmentsJSON(data []byte) ([]outboxAttachmentRef, error) {
	if len(data) == 0 || string(data) == "[]" {
		return nil, nil
	}
	var refs []outboxAttachmentRef
	if err := json.Unmarshal(data, &refs); err != nil {
		return nil, fmt.Errorf("parse outbox attachments: %w", err)
	}
	return refs, nil
}

func resolveOutboxAttachments(ctx context.Context, loader AttachmentLoader, data []byte) ([]SendAttachment, error) {
	refs, err := parseOutboxAttachmentsJSON(data)
	if err != nil {
		return nil, err
	}
	if len(refs) == 0 {
		return nil, nil
	}
	if loader == nil {
		return nil, fmt.Errorf("attachment loader not configured")
	}

	attachments := make([]SendAttachment, 0, len(refs))
	for _, ref := range refs {
		payload, err := loader.Load(ctx, ref.S3Key)
		if err != nil {
			return nil, fmt.Errorf("load attachment %q: %w", ref.Filename, err)
		}
		attachments = append(attachments, SendAttachment{
			Filename:    ref.Filename,
			ContentType: ref.ContentType,
			ContentID:   ref.ContentID,
			IsInline:    ref.IsInline,
			Data:        payload,
		})
	}
	return attachments, nil
}
