// internal/nostr/poster/poster.go
package poster

import (
	"context"
	"fmt"
	"path/filepath"
	"strings"
	"time"

	"github.com/nbd-wtf/go-nostr"
	"git.sovbit.dev/Enki/nostr-poster/internal/media/prepare"
	"git.sovbit.dev/Enki/nostr-poster/internal/nostr/events"
	"git.sovbit.dev/Enki/nostr-poster/internal/nostr/relay"
	"go.uber.org/zap"
)

// Poster handles posting content to Nostr
type Poster struct {
	eventMgr   *events.EventManager
	relayMgr   *relay.Manager
	mediaPrep  *prepare.Manager
	logger     *zap.Logger
}

// NewPoster creates a new content poster
func NewPoster(
	eventMgr *events.EventManager,
	relayMgr *relay.Manager,
	mediaPrep *prepare.Manager,
	logger *zap.Logger,
) *Poster {
	if logger == nil {
		// Create a default logger if none is provided
		var err error
		logger, err = zap.NewProduction()
		if err != nil {
			// If we can't create a logger, use a no-op logger
			logger = zap.NewNop()
		}
	}
	
	return &Poster{
		eventMgr:  eventMgr,
		relayMgr:  relayMgr,
		mediaPrep: mediaPrep,
		logger:    logger,
	}
}

// PostContent posts content to Nostr
func (p *Poster) PostContent(
	pubkey string,
	contentPath string,
	contentType string,
	mediaURL string,
	mediaHash string,
	caption string,
	hashtags []string,
) error {
	// Determine the type of content
	isImage := strings.HasPrefix(contentType, "image/")
	isVideo := strings.HasPrefix(contentType, "video/")
	
	// Create alt text if not provided (initialize it here)
	altText := caption
	if altText == "" {
		// Use the filename without extension as a fallback
		altText = strings.TrimSuffix(filepath.Base(contentPath), filepath.Ext(contentPath))
	}
	
	// Extract media dimensions if it's an image
	if isImage {
		dims, err := p.mediaPrep.GetMediaDimensions(contentPath)
		if err != nil {
			p.logger.Warn("Failed to get image dimensions, continuing anyway",
				zap.String("file", contentPath),
				zap.Error(err))
		} else {
			// Log the dimensions
			p.logger.Debug("Image dimensions", 
				zap.Int("width", dims.Width), 
				zap.Int("height", dims.Height))
			
			// Add dimensions to alt text if available
			if altText != "" {
				altText = fmt.Sprintf("%s [%dx%d]", altText, dims.Width, dims.Height)
			}
		}
	}
	
	// Create a context with timeout
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()
	
	var event *nostr.Event
	var err error
	
	// Determine the appropriate event kind and create the event
	if isImage {
		// Use kind 1 (text note) for images
		// Create hashtag string for post content
		var hashtagStr string
		if len(hashtags) > 0 {
			hashtagArr := make([]string, len(hashtags))
			for i, tag := range hashtags {
				hashtagArr[i] = "#" + tag
			}
			hashtagStr = "\n\n" + strings.Join(hashtagArr, " ")
		}
		
		content := caption + hashtagStr
		
		event, err = p.eventMgr.CreateAndSignMediaEvent(
			pubkey,
			content,
			mediaURL,
			contentType,
			mediaHash,
			altText,
			hashtags,
		)
	} else if isVideo {
		// For videos, determine if it's a short video
		isShortVideo := false // Just a placeholder, would need logic to determine
		
		// Create the video event
		event, err = p.eventMgr.CreateAndSignVideoEvent(
			pubkey,
			caption, // Title
			caption, // Description
			mediaURL,
			contentType,
			mediaHash,
			"", // Preview image URL
			0,  // Duration
			altText,
			hashtags,
			isShortVideo,
		)
	} else {
		// For other types, use a regular text note with attachment
		event, err = p.eventMgr.CreateAndSignMediaEvent(
			pubkey,
			caption,
			mediaURL,
			contentType,
			mediaHash,
			altText,
			hashtags,
		)
	}
	
	if err != nil {
		return fmt.Errorf("failed to create event: %w", err)
	}
	
	// Publish the event
	relays, err := p.relayMgr.PublishEvent(ctx, event)
	if err != nil {
		return fmt.Errorf("failed to publish event: %w", err)
	}
	
	p.logger.Info("Published content to relays",
		zap.String("event_id", event.ID),
		zap.Strings("relays", relays))
	
	return nil
}

// CreatePostContentFunc creates a function for posting content
func CreatePostContentFunc(
	eventMgr *events.EventManager,
	relayMgr *relay.Manager,
	mediaPrep *prepare.Manager,
	logger *zap.Logger,
) func(string, string, string, string, string, string, []string) error {
	poster := NewPoster(eventMgr, relayMgr, mediaPrep, logger)
	
	return func(pubkey, contentPath, contentType, mediaURL, mediaHash, caption string, hashtags []string) error {
		return poster.PostContent(pubkey, contentPath, contentType, mediaURL, mediaHash, caption, hashtags)
	}
}