// internal/config/config.go
package config

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/spf13/viper"
)

// Config holds all configuration for the application
type Config struct {
    // General configuration
    AppName    string `mapstructure:"app_name"`
    ServerPort int    `mapstructure:"server_port"`
    LogLevel   string `mapstructure:"log_level"`
    
    // Bot configuration
    Bot struct {
        KeysFile        string `mapstructure:"keys_file"`
        ContentDir      string `mapstructure:"content_dir"`
        ArchiveDir      string `mapstructure:"archive_dir"`
        DefaultInterval int    `mapstructure:"default_interval"` // in minutes
    } `mapstructure:"bot"`
    
    // Database configuration
    DB struct {
        Path string `mapstructure:"path"`
    } `mapstructure:"db"`
    
    // Media services configuration
    Media struct {
        DefaultService string `mapstructure:"default_service"` // "nip94" or "blossom"
        
        // NIP-94 configuration
        NIP94 struct {
            ServerURL   string `mapstructure:"server_url"`
            RequireAuth bool   `mapstructure:"require_auth"`
        } `mapstructure:"nip94"`
        
        // Blossom configuration
        Blossom struct {
            ServerURL string `mapstructure:"server_url"`
        } `mapstructure:"blossom"`
    } `mapstructure:"media"`
    
    // Default relays
    Relays []struct {
        URL   string `mapstructure:"url"`
        Read  bool   `mapstructure:"read"`
        Write bool   `mapstructure:"write"`
    } `mapstructure:"relays"`

    AllowedNpub string `mapstructure:"allowed_npub"` // NEW
}

// LoadConfig loads the configuration from file or environment variables
func LoadConfig(configPath string) (*Config, error) {
	v := viper.New()
	
	// Set defaults
	v.SetDefault("app_name", "Nostr Poster")
	v.SetDefault("server_port", 8765)
	v.SetDefault("log_level", "info")
	
	v.SetDefault("bot.keys_file", "keys.json")
	v.SetDefault("bot.content_dir", "./content")
	v.SetDefault("bot.archive_dir", "./archive")
	v.SetDefault("bot.default_interval", 60) // 1 hour
	
	v.SetDefault("db.path", "./nostr-poster.db")
	
	v.SetDefault("media.default_service", "nip94")
	v.SetDefault("media.nip94.require_auth", true)
	
	// Default relays
	v.SetDefault("relays", []map[string]interface{}{
		{"url": "wss://freelay.sovbit.host", "read": true, "write": true},
	})
	
	v.SetDefault("allowed_npub", "") 

	// Setup config file search
	if configPath != "" {
		// Use config file from the flag
		v.SetConfigFile(configPath)
	} else {
		// Try to find config in default locations
		v.AddConfigPath(".")
		v.AddConfigPath("./config")
		v.AddConfigPath("$HOME/.nostr-poster")
		v.SetConfigName("config")
	}
	
	// Read the config file
	v.SetConfigType("yaml")
	if err := v.ReadInConfig(); err != nil {
		if _, ok := err.(viper.ConfigFileNotFoundError); ok {
			// Config file not found, we'll create a default one
			fmt.Println("Config file not found, creating default config")
			defaultConfig := &Config{}
			v.Unmarshal(defaultConfig)
			
			// Ensure directories exist
			os.MkdirAll(filepath.Dir(v.GetString("db.path")), 0755)
			os.MkdirAll(v.GetString("bot.content_dir"), 0755)
			os.MkdirAll(v.GetString("bot.archive_dir"), 0755)
			
			// Create default config file
			if err := v.SafeWriteConfig(); err != nil {
				return nil, fmt.Errorf("failed to write default config: %w", err)
			}
		} else {
			// Config file was found but another error was produced
			return nil, fmt.Errorf("error reading config file: %w", err)
		}
	}
	
	// Environment variables can override config values
	v.SetEnvPrefix("NOSTR_POSTER")
	v.AutomaticEnv()
	
	// Parse config into struct
	config := &Config{}
	if err := v.Unmarshal(config); err != nil {
		return nil, fmt.Errorf("failed to parse config: %w", err)
	}
	
	return config, nil
}

// Save writes the current configuration to disk
func (c *Config) Save(configPath string) error {
	v := viper.New()
	
	// Convert config struct to map
	err := v.MergeConfigMap(map[string]interface{}{
		"app_name":    c.AppName,
		"server_port": c.ServerPort,
		"log_level":   c.LogLevel,
		"bot": map[string]interface{}{
			"keys_file":        c.Bot.KeysFile,
			"content_dir":      c.Bot.ContentDir,
			"archive_dir":      c.Bot.ArchiveDir,
			"default_interval": c.Bot.DefaultInterval,
		},
		"db": map[string]interface{}{
			"path": c.DB.Path,
		},
		"media": map[string]interface{}{
			"default_service": c.Media.DefaultService,
			"nip94": map[string]interface{}{
				"server_url":   c.Media.NIP94.ServerURL,
				"require_auth": c.Media.NIP94.RequireAuth,
			},
			"blossom": map[string]interface{}{
				"server_url": c.Media.Blossom.ServerURL,
			},
		},
		"relays": c.Relays,
		"allowed_npub": c.AllowedNpub,
	})
	
	if err != nil {
		return fmt.Errorf("failed to merge config: %w", err)
	}
	
	// Set the config path
	v.SetConfigFile(configPath)
	
	// Write the config file
	return v.WriteConfig()
}