package services

import (
	"context"
	"fmt"
	"os"
	"os/exec"
	"strings"
	"sync"
	"time"

	"git.linuxforward.com/byop/byop-engine/clients"
	"git.linuxforward.com/byop/byop-engine/cloud"
	"git.linuxforward.com/byop/byop-engine/config"
	"git.linuxforward.com/byop/byop-engine/dbstore"
	"git.linuxforward.com/byop/byop-engine/models"
	"github.com/sirupsen/logrus"
)

// RemotePreviewService handles remote VPS preview deployments
type RemotePreviewService struct {
	common      *PreviewCommon
	entry       *logrus.Entry
	ovhProvider cloud.Provider
	config      *config.Config
}

// NewRemotePreviewService creates a new RemotePreviewService
func NewRemotePreviewService(store *dbstore.SQLiteStore, ovhProvider cloud.Provider, cfg *config.Config, registryClient clients.RegistryClient, registryURL, registryUser, registryPass string) *RemotePreviewService {
	return &RemotePreviewService{
		common:      NewPreviewCommon(store, registryURL, registryUser, registryPass),
		entry:       logrus.WithField("service", "RemotePreviewService"),
		ovhProvider: ovhProvider,
		config:      cfg,
	}
}

// Close cleans up resources
func (rps *RemotePreviewService) Close(ctx context.Context) {
	rps.entry.Info("Cleaning up remote preview service...")
	rps.cleanupAllPreviewVPS(ctx)
	rps.common.Close()
}

// cleanupAllPreviewVPS cleans up all preview VPS instances on server shutdown
func (rps *RemotePreviewService) cleanupAllPreviewVPS(ctx context.Context) {
	rps.entry.Info("Starting cleanup of all preview VPS instances")

	// Get all VPS instances
	instances, err := rps.ovhProvider.ListInstances(ctx)
	if err != nil {
		rps.entry.WithError(err).Error("Failed to list VPS instances during cleanup")
		return
	}

	var wg sync.WaitGroup
	cleanupSemaphore := make(chan struct{}, 3) // Limit concurrent cleanup operations

	for _, instance := range instances {
		// Only clean up preview VPS instances
		if strings.Contains(instance.Name, "preview.byop.fr") {
			wg.Add(1)
			go func(inst cloud.Instance) {
				defer wg.Done()
				cleanupSemaphore <- struct{}{}        // Acquire semaphore
				defer func() { <-cleanupSemaphore }() // Release semaphore

				taskCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
				defer cancel()

				rps.entry.WithField("vps_id", inst.ID).WithField("vps_name", inst.Name).Info("Cleaning up preview VPS")

				// Stop all containers and clean up Docker images
				if inst.IPAddress != "" {
					rps.cleanupVPSResources(taskCtx, inst.IPAddress, inst.ID)
				}

				// Reset/destroy the VPS instance
				if err := rps.ovhProvider.ResetInstance(taskCtx, inst.ID); err != nil {
					rps.entry.WithField("vps_id", inst.ID).WithError(err).Error("Failed to reset preview VPS")
				} else {
					rps.entry.WithField("vps_id", inst.ID).Info("Successfully reset preview VPS")
				}
			}(instance)
		}
	}

	// Wait for all cleanup operations to complete with a timeout
	done := make(chan struct{})
	go func() {
		wg.Wait()
		close(done)
	}()

	select {
	case <-done:
		rps.entry.Info("Successfully completed cleanup of all preview VPS instances")
	case <-time.After(60 * time.Second):
		rps.entry.Warn("Timeout waiting for preview VPS cleanup to complete")
	}
}

// cleanupVPSResources cleans up all Docker resources on a VPS
func (rps *RemotePreviewService) cleanupVPSResources(ctx context.Context, ipAddress, vpsID string) {
	rps.entry.WithField("vps_id", vpsID).WithField("ip_address", ipAddress).Info("Cleaning up Docker resources on VPS")

	// Stop all preview containers
	stopAllCmd := "docker ps -q --filter 'label=byop.preview=true' | xargs -r docker stop"
	if err := rps.common.executeSSHCommand(ctx, ipAddress, stopAllCmd); err != nil {
		rps.entry.WithField("vps_id", vpsID).WithError(err).Warn("Failed to stop preview containers")
	}

	// Remove all preview containers
	removeAllCmd := "docker ps -aq --filter 'label=byop.preview=true' | xargs -r docker rm -f"
	if err := rps.common.executeSSHCommand(ctx, ipAddress, removeAllCmd); err != nil {
		rps.entry.WithField("vps_id", vpsID).WithError(err).Warn("Failed to remove preview containers")
	}

	// Remove all BYOP preview images
	removeImagesCmd := "docker images --filter 'reference=byop-preview-*' -q | xargs -r docker rmi -f"
	if err := rps.common.executeSSHCommand(ctx, ipAddress, removeImagesCmd); err != nil {
		rps.entry.WithField("vps_id", vpsID).WithError(err).Warn("Failed to remove preview images")
	}

	// Clean up all project directories
	cleanupDirsCmd := "rm -rf /home/debian/preview-*"
	if err := rps.common.executeSSHCommand(ctx, ipAddress, cleanupDirsCmd); err != nil {
		rps.entry.WithField("vps_id", vpsID).WithError(err).Warn("Failed to clean up project directories")
	}

	// Clean up temporary tar files
	cleanupTarCmd := "rm -f /tmp/byop-preview-*.tar"
	if err := rps.common.executeSSHCommand(ctx, ipAddress, cleanupTarCmd); err != nil {
		rps.entry.WithField("vps_id", vpsID).WithError(err).Warn("Failed to clean up tar files")
	}

	// Final cleanup: remove dangling images and volumes
	pruneCmd := "docker system prune -af --volumes"
	if err := rps.common.executeSSHCommand(ctx, ipAddress, pruneCmd); err != nil {
		rps.entry.WithField("vps_id", vpsID).WithError(err).Warn("Failed to prune Docker system")
	}

	rps.entry.WithField("vps_id", vpsID).Info("Completed Docker resource cleanup on VPS")
}

// CreatePreview creates a remote preview environment on a VPS
func (rps *RemotePreviewService) CreatePreview(ctx context.Context, appId uint) (*models.Preview, error) {
	// Get app details
	app, err := rps.common.GetStore().GetAppByID(ctx, appId)
	if err != nil {
		return nil, fmt.Errorf("failed to get app by ID %d: %v", appId, err)
	}

	// Create preview record
	preview := models.Preview{
		AppID:     app.ID,
		Status:    "building",
		ExpiresAt: time.Now().Add(24 * time.Hour), // 24h expiry
	}

	err = rps.common.GetStore().CreatePreview(ctx, &preview)
	if err != nil {
		return nil, fmt.Errorf("failed to create preview record: %v", err)
	}

	// Start async build and deploy to VPS
	go rps.buildAndDeployPreview(ctx, preview, app)

	return &preview, nil
}

func (rps *RemotePreviewService) buildAndDeployPreview(ctx context.Context, preview models.Preview, app *models.App) {
	rps.entry.WithField("preview_id", preview.ID).Info("Starting remote preview build and deployment")

	// Get all components for the app
	rps.entry.WithField("preview_id", preview.ID).Info("Getting app components")
	components, err := rps.common.GetAppComponents(ctx, app)
	if err != nil {
		rps.entry.WithField("preview_id", preview.ID).Errorf("Failed to get app components: %v", err)
		rps.common.UpdatePreviewStatus(ctx, preview.ID, "failed", fmt.Sprintf("Failed to get app components: %v", err))
		rps.common.GetStore().UpdateAppStatus(ctx, app.ID, "failed", fmt.Sprintf("Preview creation failed: %v", err))
		return
	}
	rps.entry.WithField("preview_id", preview.ID).WithField("component_count", len(components)).Info("Successfully retrieved app components")

	// Step 1: Build Docker images locally
	rps.entry.WithField("preview_id", preview.ID).Info("Starting Docker image build phase")
	imageNames, buildLogs, err := rps.common.BuildComponentImages(ctx, components)
	if err != nil {
		rps.entry.WithField("preview_id", preview.ID).Errorf("Failed to build component images: %v", err)
		rps.common.UpdatePreviewStatus(ctx, preview.ID, "failed", fmt.Sprintf("Failed to build images: %v", err))
		rps.common.UpdatePreviewBuildLogs(ctx, preview.ID, buildLogs)
		rps.common.GetStore().UpdateAppStatus(ctx, app.ID, "failed", fmt.Sprintf("Preview build failed: %v", err))
		return
	}
	rps.entry.WithField("preview_id", preview.ID).WithField("image_count", len(imageNames)).Info("Docker image build phase completed successfully")

	rps.common.UpdatePreviewBuildLogs(ctx, preview.ID, buildLogs)

	// Step 2: Provision preview VPS
	rps.entry.WithField("preview_id", preview.ID).Info("Starting VPS provisioning phase")
	rps.common.UpdatePreviewStatus(ctx, preview.ID, "deploying", "")

	vps, err := rps.findAvailablePreviewVPS(ctx)
	if err != nil {
		rps.entry.WithField("preview_id", preview.ID).Errorf("Failed to find available VPS: %v", err)
		rps.common.UpdatePreviewStatus(ctx, preview.ID, "failed", fmt.Sprintf("Failed to find available VPS: %v", err))
		rps.common.GetStore().UpdateAppStatus(ctx, app.ID, "failed", fmt.Sprintf("Preview VPS provisioning failed: %v", err))
		return
	}
	vpsID := vps.ID
	ipAddress := vps.IPAddress
	rps.entry.WithField("preview_id", preview.ID).WithField("vps_id", vpsID).WithField("ip_address", ipAddress).Info("VPS provisioning completed")

	// Generate preview URL with UUID
	previewUUID := rps.common.GeneratePreviewID()
	previewTLD := rps.config.PreviewTLD
	previewURL := fmt.Sprintf("https://%s.%s", previewUUID, previewTLD)
	rps.entry.WithField("preview_id", preview.ID).WithField("preview_uuid", previewUUID).WithField("preview_url", previewURL).Info("Generated remote preview URL")

	// Update preview with VPS info
	if err := rps.common.GetStore().UpdatePreviewVPS(ctx, preview.ID, vpsID, ipAddress, previewURL); err != nil {
		rps.entry.WithField("preview_id", preview.ID).Errorf("Failed to update preview VPS info: %v", err)
	}

	// Step 3: Deploy to VPS
	rps.entry.WithField("preview_id", preview.ID).Info("Starting remote deployment phase")
	deployLogs, err := rps.deployToVPS(ctx, ipAddress, imageNames, app, preview.ID, previewUUID)
	if err != nil {
		rps.entry.WithField("preview_id", preview.ID).Errorf("Failed to deploy to VPS: %v", err)
		rps.common.UpdatePreviewStatus(ctx, preview.ID, "failed", fmt.Sprintf("Failed to deploy to VPS: %v", err))
		rps.common.UpdatePreviewDeployLogs(ctx, preview.ID, deployLogs)
		rps.common.GetStore().UpdateAppStatus(ctx, app.ID, "failed", fmt.Sprintf("Remote deployment failed: %v", err))
		return
	}
	rps.entry.WithField("preview_id", preview.ID).Info("Remote deployment completed successfully")

	rps.common.UpdatePreviewDeployLogs(ctx, preview.ID, deployLogs)
	rps.common.UpdatePreviewStatus(ctx, preview.ID, "running", "")

	// Update app status to ready with preview info
	rps.common.GetStore().UpdateAppPreview(ctx, app.ID, preview.ID, previewURL)

	rps.entry.WithField("preview_id", preview.ID).WithField("vps_id", vpsID).WithField("preview_url", previewURL).Info("Remote preview deployment completed successfully")
}

// findAvailablePreviewVPS finds an existing VPS that can accommodate more previews
func (rps *RemotePreviewService) findAvailablePreviewVPS(ctx context.Context) (*cloud.Instance, error) {
	// Get all VPS instances
	instances, err := rps.ovhProvider.ListInstances(ctx)
	if err != nil {
		return nil, fmt.Errorf("failed to list VPS instances: %v", err)
	}

	// Count previews per VPS by checking all preview records
	vpsUsage := make(map[string]int)

	// Get all preview instances from database and count usage per VPS
	for _, instance := range instances {
		if strings.Contains(instance.Name, "preview.byop.fr") {
			vpsUsage[instance.ID] = 0 // Initialize to 0, will be updated below
		}
	}

	// Simple approach: look for any preview VPS that exists and return it
	maxPreviewsPerVPS := 5

	// Check if any existing VPS has capacity
	for _, instance := range instances {
		if strings.Contains(instance.Name, "preview.byop.fr") {
			currentCount := vpsUsage[instance.ID]
			if currentCount < maxPreviewsPerVPS {
				rps.entry.WithField("vps_id", instance.ID).WithField("current_previews", currentCount).Info("Found VPS with available capacity")
				return &instance, nil
			}
		}
	}

	return nil, fmt.Errorf("no available VPS with capacity found")
}

func (rps *RemotePreviewService) deployToVPS(ctx context.Context, ipAddress string, imageNames []string, app *models.App, previewID uint, previewUUID string) (string, error) {
	var logs strings.Builder

	rps.entry.WithField("ip_address", ipAddress).WithField("app_name", app.Name).WithField("preview_id", previewID).Info("Starting deployment to VPS")

	// Generate docker-compose.yml for the preview
	rps.entry.Info("Generating docker-compose.yml for preview")
	composeContent, err := rps.generatePreviewDockerCompose(imageNames, app, previewID, previewUUID)
	if err != nil {
		rps.entry.WithError(err).Error("Failed to generate docker-compose.yml")
		return logs.String(), err
	}
	logs.WriteString("Generated docker-compose.yml\n")

	// Save images to tar files and transfer to VPS
	for _, imageName := range imageNames {
		tarFile := fmt.Sprintf("/tmp/%s.tar", strings.ReplaceAll(imageName, ":", "_"))

		// Save Docker image
		rps.entry.WithField("image_name", imageName).WithField("tar_file", tarFile).Info("Saving Docker image to tar file")
		cmd := exec.CommandContext(ctx, "docker", "save", "-o", tarFile, imageName)
		if err := cmd.Run(); err != nil {
			rps.entry.WithField("image_name", imageName).WithError(err).Error("Failed to save image to tar")
			logs.WriteString(fmt.Sprintf("Failed to save image %s: %v\n", imageName, err))
			return logs.String(), err
		}
		rps.entry.WithField("image_name", imageName).Info("Successfully saved image to tar")

		// Transfer to VPS
		rps.entry.WithField("image_name", imageName).WithField("ip_address", ipAddress).Info("Transferring image to VPS")
		if err := rps.transferFile(ctx, tarFile, fmt.Sprintf("%s:/tmp/", ipAddress)); err != nil {
			rps.entry.WithField("image_name", imageName).WithError(err).Error("Failed to transfer image to VPS")
			logs.WriteString(fmt.Sprintf("Failed to transfer image %s: %v\n", imageName, err))
			return logs.String(), err
		}
		rps.entry.WithField("image_name", imageName).Info("Successfully transferred image to VPS")

		// Load image on VPS
		loadCmd := fmt.Sprintf("docker load -i /tmp/%s.tar", strings.ReplaceAll(imageName, ":", "_"))
		rps.entry.WithField("image_name", imageName).WithField("command", loadCmd).Info("Loading image on VPS")
		if err := rps.common.executeSSHCommand(ctx, ipAddress, loadCmd); err != nil {
			rps.entry.WithField("image_name", imageName).WithError(err).Error("Failed to load image on VPS")
			logs.WriteString(fmt.Sprintf("Failed to load image %s on VPS: %v\n", imageName, err))
			return logs.String(), err
		}
		rps.entry.WithField("image_name", imageName).Info("Successfully loaded image on VPS")

		// Clean up local tar file
		os.Remove(tarFile)
		rps.entry.WithField("tar_file", tarFile).Info("Cleaned up local tar file")
	}

	// Create project-specific directory and transfer docker-compose.yml
	projectName := fmt.Sprintf("preview-%d", previewID)
	projectDir := fmt.Sprintf("/home/debian/%s", projectName)

	// Create project directory on VPS
	rps.entry.WithField("project_dir", projectDir).Info("Creating project directory on VPS")
	if err := rps.common.executeSSHCommand(ctx, ipAddress, fmt.Sprintf("mkdir -p %s", projectDir)); err != nil {
		rps.entry.WithError(err).Error("Failed to create project directory on VPS")
		return logs.String(), err
	}

	composeFile := "/tmp/docker-compose-preview.yml"
	rps.entry.WithField("compose_file", composeFile).Info("Writing docker-compose.yml to temporary file")
	if err := os.WriteFile(composeFile, []byte(composeContent), 0644); err != nil {
		rps.entry.WithError(err).Error("Failed to write docker-compose.yml")
		return logs.String(), err
	}

	rps.entry.WithField("ip_address", ipAddress).WithField("project_dir", projectDir).Info("Transferring docker-compose.yml to VPS")
	if err := rps.transferFile(ctx, composeFile, fmt.Sprintf("%s:%s/docker-compose.yml", ipAddress, projectDir)); err != nil {
		rps.entry.WithError(err).Error("Failed to transfer docker-compose.yml to VPS")
		logs.WriteString(fmt.Sprintf("Failed to transfer docker-compose.yml: %v\n", err))
		return logs.String(), err
	}
	rps.entry.Info("Successfully transferred docker-compose.yml to VPS")

	// Start services on VPS with project-specific naming
	rps.entry.WithField("ip_address", ipAddress).WithField("project_name", projectName).Info("Starting services on VPS with docker-compose")
	startCmd := fmt.Sprintf("cd %s && docker compose -p %s up -d", projectDir, projectName)
	if err := rps.common.executeSSHCommand(ctx, ipAddress, startCmd); err != nil {
		rps.entry.WithError(err).Error("Failed to start services on VPS")
		logs.WriteString(fmt.Sprintf("Failed to start services: %v\n", err))
		return logs.String(), err
	}
	rps.entry.Info("Successfully started services on VPS")

	// Validate DNS and certificate setup for debugging
	previewDomain := fmt.Sprintf("%s.%s", previewUUID, rps.config.PreviewTLD)
	rps.validateDNSAndCertificate(ctx, previewDomain, ipAddress)

	rps.entry.WithField("ip_address", ipAddress).WithField("project_name", projectName).Info("Remote preview deployment completed successfully")
	logs.WriteString("Remote preview deployment completed successfully\n")
	return logs.String(), nil
}

func (rps *RemotePreviewService) generatePreviewDockerCompose(imageNames []string, app *models.App, previewID uint, previewUUID string) (string, error) {
	rps.entry.WithField("app_id", app.ID).WithField("preview_id", previewID).WithField("image_count", len(imageNames)).Info("Generating docker-compose content for remote deployment")

	compose := "services:\n"

	for i, imageName := range imageNames {
		serviceName := fmt.Sprintf("service-%d", i)
		compose += fmt.Sprintf("  %s:\n", serviceName)
		compose += fmt.Sprintf("    image: %s\n", imageName)
		compose += "    restart: unless-stopped\n"
		compose += "    environment:\n"
		compose += "      - NODE_ENV=preview\n"
		compose += fmt.Sprintf("      - APP_NAME=%s\n", app.Name)

		// Add BYOP preview labels for tracking
		compose += "    labels:\n"
		compose += "      - \"byop.preview=true\"\n"
		compose += fmt.Sprintf("      - \"byop.app.id=%d\"\n", app.ID)
		compose += fmt.Sprintf("      - \"byop.app.name=%s\"\n", app.Name)
		compose += fmt.Sprintf("      - \"byop.preview.id=%d\"\n", previewID)

		// Add Traefik labels for the first service (main entry point)
		if i == 0 {
			previewDomain := fmt.Sprintf("%s.%s", previewUUID, rps.config.PreviewTLD)
			routerName := fmt.Sprintf("preview-%d-%s", previewID, previewUUID)
			compose += "      - \"traefik.enable=true\"\n"
			compose += fmt.Sprintf("      - \"traefik.http.routers.%s.rule=Host(`%s`)\"\n", routerName, previewDomain)
			compose += fmt.Sprintf("      - \"traefik.http.routers.%s.entrypoints=websecure\"\n", routerName)
			compose += fmt.Sprintf("      - \"traefik.http.routers.%s.tls=true\"\n", routerName)
			compose += fmt.Sprintf("      - \"traefik.http.routers.%s.tls.certresolver=tlsresolver\"\n", routerName)
			compose += "      - \"traefik.docker.network=traefik\"\n"
		}

		compose += "    networks:\n"
		compose += "      - traefik\n"
		compose += "\n"
	}

	// Add networks section
	compose += "networks:\n"
	compose += "  traefik:\n"
	compose += "    external: true\n"

	return compose, nil
}

// DeletePreview deletes a remote preview
func (rps *RemotePreviewService) DeletePreview(ctx context.Context, appID uint) error {
	// Get the preview to ensure it exists
	preview, err := rps.common.GetStore().GetPreviewByAppID(ctx, appID)
	if err != nil {
		return fmt.Errorf("failed to get preview by app ID %d: %v", appID, err)
	}

	if preview == nil {
		return fmt.Errorf("preview with app ID %d not found", appID)
	}

	rps.entry.WithField("preview_id", preview.ID).Info("Deleting remote preview")

	// Stop and remove containers on VPS using project-specific naming
	if preview.IPAddress != "" && preview.IPAddress != "127.0.0.1" {
		projectName := fmt.Sprintf("preview-%d", preview.ID)
		projectDir := fmt.Sprintf("/home/debian/%s", projectName)

		// Stop containers with project-specific naming
		stopCmd := fmt.Sprintf("cd %s && docker compose -p %s down --remove-orphans", projectDir, projectName)
		rps.common.executeSSHCommand(ctx, preview.IPAddress, stopCmd)

		// Remove project directory
		rmCmd := fmt.Sprintf("rm -rf %s", projectDir)
		rps.common.executeSSHCommand(ctx, preview.IPAddress, rmCmd)

		// Cleanup Docker images
		if err := rps.common.CleanupPreviewImagesForApp(ctx, appID, true, preview.IPAddress); err != nil {
			rps.entry.WithField("preview_id", preview.ID).WithError(err).Warn("Failed to clean up Docker images")
		}
	}

	// Don't remove the VPS instance - it might be hosting other previews
	// Only clean up if this is the last preview on the VPS
	if preview.VPSID != "" && !strings.Contains(preview.VPSID, "byop.local") {
		// Check if there are other active previews on this VPS
		otherPreviews, err := rps.getActivePreviewsOnVPS(ctx, preview.VPSID)
		if err != nil {
			rps.entry.WithField("vps_id", preview.VPSID).Warnf("Failed to check other previews on VPS: %v", err)
		} else if len(otherPreviews) <= 1 { // Only this preview remains
			if err := rps.ovhProvider.ResetInstance(ctx, preview.VPSID); err != nil {
				rps.entry.WithField("vps_id", preview.VPSID).Errorf("Failed to reset VPS instance: %v", err)
			}
		}
	}

	// Delete the preview record from the database
	if err := rps.common.GetStore().DeletePreview(ctx, preview.ID); err != nil {
		return fmt.Errorf("failed to delete preview from database: %v", err)
	}

	rps.entry.WithField("preview_id", preview.ID).Info("Successfully deleted remote preview")
	return nil
}

// StopPreview stops a remote preview
func (rps *RemotePreviewService) StopPreview(ctx context.Context, previewID uint) error {
	preview, err := rps.common.GetStore().GetPreviewByID(ctx, previewID)
	if err != nil {
		return err
	}

	if preview == nil {
		return fmt.Errorf("preview not found")
	}

	// Stop containers on VPS
	projectName := fmt.Sprintf("preview-%d", previewID)
	projectDir := fmt.Sprintf("/home/debian/%s", projectName)
	stopCmd := fmt.Sprintf("cd %s && docker compose -p %s down --remove-orphans", projectDir, projectName)
	rps.common.executeSSHCommand(ctx, preview.IPAddress, stopCmd)

	// Clean up Docker images before destroying VPS
	if err := rps.common.CleanupPreviewImagesForApp(ctx, preview.AppID, true, preview.IPAddress); err != nil {
		rps.entry.WithField("preview_id", previewID).WithError(err).Warn("Failed to clean up Docker images")
	}

	// Destroy the VPS
	if err := rps.ovhProvider.ResetInstance(ctx, preview.VPSID); err != nil {
		rps.entry.WithField("vps_id", preview.VPSID).Errorf("Failed to destroy preview VPS: %v", err)
	}

	return rps.common.GetStore().UpdatePreviewStatus(ctx, previewID, "stopped", "")
}

// getActivePreviewsOnVPS returns all active previews running on a specific VPS
func (rps *RemotePreviewService) getActivePreviewsOnVPS(ctx context.Context, vpsID string) ([]*models.Preview, error) {
	apps, err := rps.common.GetStore().GetAllApps(ctx)
	if err != nil {
		return nil, fmt.Errorf("failed to get apps: %v", err)
	}

	var activePreviews []*models.Preview
	for _, app := range apps {
		previews, err := rps.common.GetStore().GetPreviewsByAppID(ctx, app.ID)
		if err != nil {
			continue
		}

		for _, preview := range previews {
			if preview.VPSID == vpsID && preview.Status == "running" {
				activePreviews = append(activePreviews, preview)
			}
		}
	}

	return activePreviews, nil
}

// Helper methods - using common SSH command execution

func (rps *RemotePreviewService) transferFile(ctx context.Context, localPath, remotePath string) error {
	hostAndPath := strings.SplitN(remotePath, ":", 2)
	if len(hostAndPath) != 2 {
		return fmt.Errorf("invalid SCP destination format: %s", remotePath)
	}
	remoteHost := hostAndPath[0]
	remotePath = hostAndPath[1]

	cmd := exec.CommandContext(ctx, "scp", "-o", "StrictHostKeyChecking=no", localPath, fmt.Sprintf("debian@%s:%s", remoteHost, remotePath))

	output, err := cmd.CombinedOutput()
	if err != nil {
		rps.entry.WithField("local_path", localPath).WithField("remote_path", remotePath).WithField("output", string(output)).WithError(err).Error("SCP transfer failed")
		return err
	}

	rps.entry.WithField("local_path", localPath).WithField("remote_path", remotePath).Info("Successfully transferred file")
	return nil
}

// validateDNSAndCertificate validates DNS resolution and Traefik certificate for debugging
func (rps *RemotePreviewService) validateDNSAndCertificate(ctx context.Context, previewDomain, ipAddress string) {
	rps.entry.WithField("domain", previewDomain).WithField("ip_address", ipAddress).Info("Validating DNS and certificate setup")

	// Check DNS resolution from the VPS
	dnsCmd := fmt.Sprintf("nslookup %s", previewDomain)
	if err := rps.common.executeSSHCommand(ctx, ipAddress, dnsCmd); err != nil {
		rps.entry.WithField("domain", previewDomain).WithError(err).Warn("DNS resolution failed from VPS")
	}

	// Check if Traefik can see the service
	traefikCmd := "docker ps --filter 'label=traefik.enable=true' --format 'table {{.Names}}\t{{.Labels}}'"
	if err := rps.common.executeSSHCommand(ctx, ipAddress, traefikCmd); err != nil {
		rps.entry.WithError(err).Warn("Failed to check Traefik-enabled containers")
	}

	// Check Traefik logs for certificate issues
	logsCmd := "docker logs traefik --tail 20"
	if err := rps.common.executeSSHCommand(ctx, ipAddress, logsCmd); err != nil {
		rps.entry.WithError(err).Warn("Failed to get Traefik logs")
	}

	// Wait a bit for DNS propagation and certificate generation
	rps.entry.WithField("domain", previewDomain).Info("Waiting 30 seconds for DNS propagation and certificate generation")
	time.Sleep(30 * time.Second)
}
