package content import ( "fmt" "log" "os" "path/filepath" "strings" "sync" "github.com/insertr/insertr/internal/config" "github.com/insertr/insertr/internal/db" "github.com/insertr/insertr/internal/engine" "maps" ) // SiteManager handles registration and enhancement of static sites type SiteManager struct { sites map[string]*config.SiteConfig enhancer *Enhancer mutex sync.RWMutex devMode bool contentClient db.ContentRepository authProvider *engine.AuthProvider } // NewSiteManager creates a new site manager func NewSiteManager(contentClient db.ContentRepository, devMode bool) *SiteManager { return &SiteManager{ sites: make(map[string]*config.SiteConfig), enhancer: NewDefaultEnhancer(contentClient, ""), // siteID will be set per operation devMode: devMode, contentClient: contentClient, authProvider: &engine.AuthProvider{Type: "mock"}, // default } } // NewSiteManagerWithAuth creates a new site manager with auth provider func NewSiteManagerWithAuth(contentClient db.ContentRepository, devMode bool, authProvider *engine.AuthProvider) *SiteManager { if authProvider == nil { authProvider = &engine.AuthProvider{Type: "mock"} } return &SiteManager{ sites: make(map[string]*config.SiteConfig), contentClient: contentClient, authProvider: authProvider, devMode: devMode, } } // RegisterSite adds a site to the manager func (sm *SiteManager) RegisterSite(config *config.SiteConfig) error { sm.mutex.Lock() defer sm.mutex.Unlock() // Validate site configuration if config.SiteID == "" { return fmt.Errorf("site_id is required") } if config.Path == "" { return fmt.Errorf("path is required for site %s", config.SiteID) } // Check if path exists, auto-create enhancement directories if _, err := os.Stat(config.Path); os.IsNotExist(err) { // Auto-create directory if it appears to be an enhancement target if strings.HasSuffix(config.Path, "_enhanced") { log.Printf("📁 Creating enhancement directory: %s", config.Path) if err := os.MkdirAll(config.Path, 0755); err != nil { return fmt.Errorf("failed to create enhancement directory %s: %w", config.Path, err) } } else { return fmt.Errorf("site path does not exist: %s", config.Path) } } // Convert to absolute path absPath, err := filepath.Abs(config.Path) if err != nil { return fmt.Errorf("failed to resolve absolute path for %s: %w", config.Path, err) } config.Path = absPath sm.sites[config.SiteID] = config log.Printf("📁 Registered site %s at %s", config.SiteID, config.Path) return nil } // RegisterSites bulk registers multiple sites from configuration func (sm *SiteManager) RegisterSites(configs []*config.SiteConfig) error { for _, config := range configs { if err := sm.RegisterSite(config); err != nil { return fmt.Errorf("failed to register site %s: %w", config.SiteID, err) } } return nil } // GetSite returns a registered site configuration func (sm *SiteManager) GetSite(siteID string) (*config.SiteConfig, bool) { sm.mutex.RLock() defer sm.mutex.RUnlock() site, exists := sm.sites[siteID] return site, exists } // GetAllSites returns all registered sites func (sm *SiteManager) GetAllSites() map[string]*config.SiteConfig { sm.mutex.RLock() defer sm.mutex.RUnlock() // Return a copy to prevent external modification result := make(map[string]*config.SiteConfig) maps.Copy(result, sm.sites) return result } // IsAutoEnhanceEnabled checks if a site has auto-enhancement enabled func (sm *SiteManager) IsAutoEnhanceEnabled(siteID string) bool { sm.mutex.RLock() defer sm.mutex.RUnlock() site, exists := sm.sites[siteID] return exists && site.AutoEnhance } // EnhanceSite performs enhancement from source to output directory func (sm *SiteManager) EnhanceSite(siteID string) error { sm.mutex.RLock() site, exists := sm.sites[siteID] sm.mutex.RUnlock() if !exists { return fmt.Errorf("site %s is not registered", siteID) } // Use source path if available, otherwise use main path (for backwards compatibility) sourcePath := site.SourcePath if sourcePath == "" { sourcePath = site.Path } outputPath := site.Path log.Printf("🔄 Enhancing site %s from %s to %s", siteID, sourcePath, outputPath) // Create output directory if it doesn't exist if err := os.MkdirAll(outputPath, 0755); err != nil { return fmt.Errorf("failed to create output directory %s: %w", outputPath, err) } // Create enhancer with auth provider for this operation // Discovery disabled by default - developers should explicitly mark elements with class="insertr" discoveryConfig := DiscoveryConfig{ Enabled: false, // Changed from true - respect developer intent Aggressive: false, Containers: true, Individual: true, } // Override with site-specific discovery config if provided if site.Discovery != nil { discoveryConfig = *site.Discovery log.Printf("🔧 Using site-specific discovery config for %s: enabled=%v, aggressive=%v", siteID, discoveryConfig.Enabled, discoveryConfig.Aggressive) } config := EnhancementConfig{ Discovery: discoveryConfig, ContentInjection: true, GenerateIDs: true, } enhancer := NewEnhancerWithAuth(sm.contentClient, siteID, config, sm.authProvider) // Perform enhancement from source to output if err := enhancer.EnhanceDirectory(sourcePath, outputPath); err != nil { return fmt.Errorf("failed to enhance site %s: %w", siteID, err) } log.Printf("✅ Successfully enhanced site %s", siteID) return nil } // EnhanceAllSites enhances all registered sites that have auto-enhancement enabled func (sm *SiteManager) EnhanceAllSites() error { sm.mutex.RLock() sites := make([]*config.SiteConfig, 0, len(sm.sites)) for _, site := range sm.sites { if site.AutoEnhance { sites = append(sites, site) } } sm.mutex.RUnlock() var errors []error for _, site := range sites { if err := sm.EnhanceSite(site.SiteID); err != nil { errors = append(errors, err) } } if len(errors) > 0 { return fmt.Errorf("enhancement failed for some sites: %v", errors) } return nil } // GetStats returns statistics about registered sites func (sm *SiteManager) GetStats() map[string]any { sm.mutex.RLock() defer sm.mutex.RUnlock() autoEnhanceCount := 0 for _, site := range sm.sites { if site.AutoEnhance { autoEnhanceCount++ } } return map[string]interface{}{ "total_sites": len(sm.sites), "auto_enhance_sites": autoEnhanceCount, } }