package eventlogger

import (
	"context"
	"fmt"
	"strings"
	"sync"

	"git.warky.dev/wdevs/whatshooked/pkg/config"
	"git.warky.dev/wdevs/whatshooked/pkg/events"
	"git.warky.dev/wdevs/whatshooked/pkg/logging"
	"go.mau.fi/whatsmeow/types"
)

// Logger handles event logging to multiple targets
type Logger struct {
	config   config.EventLoggerConfig
	dbConfig config.DatabaseConfig
	targets  []Target
	mu       sync.Mutex
}

// Target represents a logging target
type Target interface {
	Log(event events.Event) error
	Close() error
}

// WhatsAppManager interface for MQTT target
type WhatsAppManager interface {
	SendTextMessage(ctx context.Context, accountID string, jid types.JID, text string) error
	SendImage(ctx context.Context, accountID string, jid types.JID, imageData []byte, mimeType string, caption string) error
	SendVideo(ctx context.Context, accountID string, jid types.JID, videoData []byte, mimeType string, caption string) error
	SendDocument(ctx context.Context, accountID string, jid types.JID, documentData []byte, mimeType string, filename string, caption string) error
}

// NewLogger creates a new event logger
func NewLogger(cfg config.EventLoggerConfig, dbConfig config.DatabaseConfig, waManager WhatsAppManager, defaultCountryCode string) (*Logger, error) {
	logger := &Logger{
		config:   cfg,
		dbConfig: dbConfig,
		targets:  make([]Target, 0),
	}

	// Initialize targets based on configuration
	for _, targetType := range cfg.Targets {
		switch strings.ToLower(targetType) {
		case "file":
			fileTarget, err := NewFileTarget(cfg.FileDir)
			if err != nil {
				logging.Error("Failed to initialize file target", "error", err)
				continue
			}
			logger.targets = append(logger.targets, fileTarget)
			logging.Info("Event logger file target initialized", "dir", cfg.FileDir)

		case "sqlite":
			sqliteTarget, err := NewSQLiteTarget(dbConfig, cfg.TableName)
			if err != nil {
				logging.Error("Failed to initialize SQLite target", "error", err)
				continue
			}
			logger.targets = append(logger.targets, sqliteTarget)
			logging.Info("Event logger SQLite target initialized")

		case "postgres", "postgresql":
			postgresTarget, err := NewPostgresTarget(dbConfig, cfg.TableName)
			if err != nil {
				logging.Error("Failed to initialize PostgreSQL target", "error", err)
				continue
			}
			logger.targets = append(logger.targets, postgresTarget)
			logging.Info("Event logger PostgreSQL target initialized")

		case "mqtt":
			logging.Info("Initializing MQTT event logger target", "broker", cfg.MQTT.Broker)
			mqttTarget, err := NewMQTTTarget(cfg.MQTT, waManager, defaultCountryCode)
			if err != nil {
				logging.Error("Failed to initialize MQTT target", "error", err)
				continue
			}
			logger.targets = append(logger.targets, mqttTarget)
			logging.Info("Event logger MQTT target initialized")

		default:
			logging.Error("Unknown event logger target type", "type", targetType)
		}
	}

	return logger, nil
}

// Log logs an event to all configured targets
func (l *Logger) Log(event events.Event) {
	l.mu.Lock()
	defer l.mu.Unlock()

	for _, target := range l.targets {
		if err := target.Log(event); err != nil {
			logging.Error("Failed to log event", "target", fmt.Sprintf("%T", target), "error", err)
		}
	}
}

// Close closes all logging targets
func (l *Logger) Close() error {
	l.mu.Lock()
	defer l.mu.Unlock()

	var errors []string
	for _, target := range l.targets {
		if err := target.Close(); err != nil {
			errors = append(errors, err.Error())
		}
	}

	if len(errors) > 0 {
		return fmt.Errorf("errors closing targets: %s", strings.Join(errors, "; "))
	}

	return nil
}
