package main

import (
	"context"
	"flag"
	"fmt"
	"os"
	"os/signal"
	"syscall"
	"time"

	"veza-backend-api/internal/services"

	"go.uber.org/zap"
)

func main() {
	// Parse command line flags
	backupDir := flag.String("backup-dir", "/backups/postgres", "Directory to store backups")
	retentionDays := flag.Int("retention-days", 30, "Number of days to retain backups")
	createBackup := flag.Bool("create", false, "Create a new backup")
	cleanup := flag.Bool("cleanup", false, "Cleanup old backups")
	list := flag.Bool("list", false, "List all backups")
	flag.Parse()

	// Initialize logger
	logger, err := zap.NewProduction()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to initialize logger: %v\n", err)
		os.Exit(1)
	}
	defer logger.Sync()

	// Get database connection details from environment variables
	databaseURL := os.Getenv("DATABASE_URL")
	databaseName := os.Getenv("DB_NAME")
	if databaseName == "" {
		databaseName = "veza_db" // Default
	}
	databaseUser := os.Getenv("DB_USER")
	if databaseUser == "" {
		databaseUser = "veza_user" // Default
	}
	databaseHost := os.Getenv("DB_HOST")
	if databaseHost == "" {
		databaseHost = "localhost" // Default
	}
	databasePort := os.Getenv("DB_PORT")
	if databasePort == "" {
		databasePort = "5432" // Default
	}

	// If DATABASE_URL is not set, try to construct it from individual components
	if databaseURL == "" {
		// Use individual components for pg_dump
	}

	// Create backup service
	backupConfig := services.BackupConfig{
		BackupDir:     *backupDir,
		RetentionDays: *retentionDays,
		DatabaseURL:   databaseURL,
		DatabaseName:  databaseName,
		DatabaseUser:  databaseUser,
		DatabaseHost:  databaseHost,
		DatabasePort:  databasePort,
	}

	backupService, err := services.NewBackupService(backupConfig, logger)
	if err != nil {
		logger.Fatal("Failed to create backup service", zap.Error(err))
	}

	// Create context with timeout
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Minute)
	defer cancel()

	// Handle signals for graceful shutdown
	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)

	go func() {
		<-sigChan
		logger.Info("Received shutdown signal, cancelling backup operation")
		cancel()
	}()

	// Execute requested action
	if *createBackup {
		logger.Info("Creating database backup")
		result, err := backupService.CreateBackup(ctx)
		if err != nil {
			logger.Fatal("Backup failed", zap.Error(err))
		}

		if result.Success {
			logger.Info("Backup completed successfully",
				zap.String("backup_path", result.BackupPath),
				zap.Int64("backup_size", result.BackupSize),
				zap.Duration("duration", result.Duration))
		} else {
			logger.Fatal("Backup failed", zap.String("error", result.ErrorMessage))
		}
	} else if *cleanup {
		logger.Info("Cleaning up old backups")
		if err := backupService.CleanupOldBackups(ctx); err != nil {
			logger.Fatal("Cleanup failed", zap.Error(err))
		}
		logger.Info("Cleanup completed successfully")
	} else if *list {
		logger.Info("Listing backups")
		backups, err := backupService.ListBackups(ctx)
		if err != nil {
			logger.Fatal("Failed to list backups", zap.Error(err))
		}

		fmt.Printf("\nFound %d backups:\n\n", len(backups))
		for _, backup := range backups {
			sizeMB := float64(backup.Size) / (1024 * 1024)
			fmt.Printf("  %s\n", backup.FileName)
			fmt.Printf("    Path: %s\n", backup.FilePath)
			fmt.Printf("    Size: %.2f MB\n", sizeMB)
			fmt.Printf("    Created: %s\n\n", backup.CreatedAt.Format(time.RFC3339))
		}
	} else {
		// Default: create backup and cleanup
		logger.Info("Creating backup and cleaning up old backups")

		result, err := backupService.CreateBackup(ctx)
		if err != nil {
			logger.Fatal("Backup failed", zap.Error(err))
		}

		if result.Success {
			logger.Info("Backup completed successfully",
				zap.String("backup_path", result.BackupPath),
				zap.Int64("backup_size", result.BackupSize),
				zap.Duration("duration", result.Duration))
		}

		// Cleanup old backups
		if err := backupService.CleanupOldBackups(ctx); err != nil {
			logger.Warn("Cleanup failed", zap.Error(err))
		}
	}
}
