package content

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"sync"
	"time"
)

// SiteConfig represents configuration for a registered site
type SiteConfig struct {
	SiteID          string `yaml:"site_id"`
	Path            string `yaml:"path"`
	Domain          string `yaml:"domain,omitempty"`
	AutoEnhance     bool   `yaml:"auto_enhance"`
	BackupOriginals bool   `yaml:"backup_originals"`
}

// SiteManager handles registration and enhancement of static sites
type SiteManager struct {
	sites     map[string]*SiteConfig
	enhancer  *Enhancer
	mutex     sync.RWMutex
	backupDir string
	devMode   bool
}

// NewSiteManager creates a new site manager
func NewSiteManager(contentClient ContentClient, backupDir string, devMode bool) *SiteManager {
	if backupDir == "" {
		backupDir = "./insertr-backups"
	}

	return &SiteManager{
		sites:     make(map[string]*SiteConfig),
		enhancer:  NewEnhancer(contentClient, ""), // siteID will be set per operation
		backupDir: backupDir,
		devMode:   devMode,
	}
}

// RegisterSite adds a site to the manager
func (sm *SiteManager) RegisterSite(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
	if _, err := os.Stat(config.Path); os.IsNotExist(err) {
		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 []*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) (*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]*SiteConfig {
	sm.mutex.RLock()
	defer sm.mutex.RUnlock()

	// Return a copy to prevent external modification
	result := make(map[string]*SiteConfig)
	for id, site := range sm.sites {
		result[id] = site
	}
	return result
}

// IsAutoEnhanceEnabled checks if a site has auto-enhancement enabled
func (sm *SiteManager) IsAutoEnhanceEnabled(siteID string) bool {
	// Never auto-enhance in development mode - use manual enhance button instead
	if sm.devMode {
		return false
	}

	sm.mutex.RLock()
	defer sm.mutex.RUnlock()

	site, exists := sm.sites[siteID]
	return exists && site.AutoEnhance
}

// EnhanceSite performs in-place enhancement of a registered site
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)
	}

	log.Printf("🔄 Enhancing site %s at %s", siteID, site.Path)

	// Create backup if enabled
	if site.BackupOriginals {
		if err := sm.createBackup(siteID, site.Path); err != nil {
			log.Printf("⚠️ Failed to create backup for site %s: %v", siteID, err)
			// Continue with enhancement even if backup fails
		}
	}

	// Perform in-place enhancement
	if err := sm.enhancer.EnhanceInPlace(site.Path, siteID); 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([]*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
}

// createBackup creates a timestamped backup of the site
func (sm *SiteManager) createBackup(siteID, sitePath string) error {
	// Create backup directory structure
	timestamp := time.Now().Format("20060102-150405")
	backupPath := filepath.Join(sm.backupDir, siteID, timestamp)

	if err := os.MkdirAll(backupPath, 0755); err != nil {
		return fmt.Errorf("failed to create backup directory: %w", err)
	}

	// Copy HTML files to backup
	return filepath.Walk(sitePath, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		// Only backup HTML files
		if !info.IsDir() && filepath.Ext(path) == ".html" {
			relPath, err := filepath.Rel(sitePath, path)
			if err != nil {
				return err
			}

			backupFilePath := filepath.Join(backupPath, relPath)

			// Create directory structure in backup
			if err := os.MkdirAll(filepath.Dir(backupFilePath), 0755); err != nil {
				return err
			}

			// Copy file
			content, err := os.ReadFile(path)
			if err != nil {
				return err
			}

			return os.WriteFile(backupFilePath, content, info.Mode())
		}

		return nil
	})
}

// RestoreFromBackup restores a site from a specific backup
func (sm *SiteManager) RestoreFromBackup(siteID, timestamp string) error {
	sm.mutex.RLock()
	site, exists := sm.sites[siteID]
	sm.mutex.RUnlock()

	if !exists {
		return fmt.Errorf("site %s is not registered", siteID)
	}

	backupPath := filepath.Join(sm.backupDir, siteID, timestamp)
	if _, err := os.Stat(backupPath); os.IsNotExist(err) {
		return fmt.Errorf("backup not found: %s", backupPath)
	}

	log.Printf("🔄 Restoring site %s from backup %s", siteID, timestamp)

	// Copy backup files back to site directory
	return filepath.Walk(backupPath, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		if !info.IsDir() {
			relPath, err := filepath.Rel(backupPath, path)
			if err != nil {
				return err
			}

			targetPath := filepath.Join(site.Path, relPath)

			// Create directory structure
			if err := os.MkdirAll(filepath.Dir(targetPath), 0755); err != nil {
				return err
			}

			// Copy file
			content, err := os.ReadFile(path)
			if err != nil {
				return err
			}

			return os.WriteFile(targetPath, content, info.Mode())
		}

		return nil
	})
}

// ListBackups returns available backups for a site
func (sm *SiteManager) ListBackups(siteID string) ([]string, error) {
	backupSitePath := filepath.Join(sm.backupDir, siteID)

	if _, err := os.Stat(backupSitePath); os.IsNotExist(err) {
		return []string{}, nil // No backups exist
	}

	entries, err := os.ReadDir(backupSitePath)
	if err != nil {
		return nil, fmt.Errorf("failed to read backup directory: %w", err)
	}

	var backups []string
	for _, entry := range entries {
		if entry.IsDir() {
			backups = append(backups, entry.Name())
		}
	}

	return backups, nil
}

// GetStats returns statistics about registered sites
func (sm *SiteManager) GetStats() map[string]interface{} {
	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,
		"backup_directory":   sm.backupDir,
	}
}
