package cmd

import (
	"context"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"time"

	"dbbackup/internal/cloud"
	"dbbackup/internal/metadata"
	"dbbackup/internal/restore"
	"dbbackup/internal/verification"

	"github.com/spf13/cobra"
)

var verifyBackupCmd = &cobra.Command{
	Use:   "verify-backup [backup-file]",
	Short: "Verify backup file integrity with checksums",
	Long: `Verify the integrity of one or more backup files by comparing their SHA-256 checksums
against the stored metadata. This ensures that backups have not been corrupted.

Examples:
  # Verify a single backup
  dbbackup verify-backup /backups/mydb_20260115.dump

  # Verify all backups in a directory
  dbbackup verify-backup /backups/*.dump

  # Quick verification (size check only, no checksum)
  dbbackup verify-backup /backups/mydb.dump --quick

  # Verify and show detailed information
  dbbackup verify-backup /backups/mydb.dump --verbose`,
	Args: cobra.MinimumNArgs(1),
	RunE: runVerifyBackup,
}

var (
	quickVerify   bool
	verboseVerify bool
)

func init() {
	rootCmd.AddCommand(verifyBackupCmd)
	verifyBackupCmd.Flags().BoolVar(&quickVerify, "quick", false, "Quick verification (size check only)")
	verifyBackupCmd.Flags().BoolVarP(&verboseVerify, "verbose", "v", false, "Show detailed information")
}

func runVerifyBackup(cmd *cobra.Command, args []string) error {
	// Check if any argument is a cloud URI
	hasCloudURI := false
	for _, arg := range args {
		if isCloudURI(arg) {
			hasCloudURI = true
			break
		}
	}

	// If cloud URIs detected, handle separately
	if hasCloudURI {
		return runVerifyCloudBackup(cmd, args)
	}

	// Expand glob patterns for local files
	var backupFiles []string
	for _, pattern := range args {
		matches, err := filepath.Glob(pattern)
		if err != nil {
			return fmt.Errorf("invalid pattern %s: %w", pattern, err)
		}
		if len(matches) == 0 {
			// Not a glob, use as-is
			backupFiles = append(backupFiles, pattern)
		} else {
			backupFiles = append(backupFiles, matches...)
		}
	}

	if len(backupFiles) == 0 {
		return fmt.Errorf("no backup files found")
	}

	fmt.Printf("Verifying %d backup file(s)...\n\n", len(backupFiles))

	successCount := 0
	failureCount := 0

	for _, backupFile := range backupFiles {
		// Skip metadata files
		if strings.HasSuffix(backupFile, ".meta.json") ||
			strings.HasSuffix(backupFile, ".sha256") ||
			strings.HasSuffix(backupFile, ".info") {
			continue
		}

		fmt.Printf("[FILE] %s\n", filepath.Base(backupFile))

		if quickVerify {
			// Quick check: size only
			err := verification.QuickCheck(backupFile)
			if err != nil {
				fmt.Printf("   [FAIL] FAILED: %v\n\n", err)
				failureCount++
				continue
			}
			fmt.Printf("   [OK] VALID (quick check)\n\n")
			successCount++
		} else {
			// Full verification with SHA-256
			result, err := verification.Verify(backupFile)
			if err != nil {
				return fmt.Errorf("verification error: %w", err)
			}

			if result.Valid {
				fmt.Printf("   [OK] VALID\n")
				if verboseVerify {
					meta, _ := metadata.Load(backupFile)
					fmt.Printf("   Size: %s\n", metadata.FormatSize(meta.SizeBytes))
					fmt.Printf("   SHA-256: %s\n", meta.SHA256)
					fmt.Printf("   Database: %s (%s)\n", meta.Database, meta.DatabaseType)
					fmt.Printf("   Created: %s\n", meta.Timestamp.Format(time.RFC3339))
				}
				fmt.Println()
				successCount++
			} else {
				fmt.Printf("   [FAIL] FAILED: %v\n", result.Error)
				if verboseVerify {
					if !result.FileExists {
						fmt.Printf("   File does not exist\n")
					} else if !result.MetadataExists {
						fmt.Printf("   Metadata file missing\n")
					} else if !result.SizeMatch {
						fmt.Printf("   Size mismatch\n")
					} else {
						fmt.Printf("   Expected: %s\n", result.ExpectedSHA256)
						fmt.Printf("   Got:      %s\n", result.CalculatedSHA256)
					}
				}
				fmt.Println()
				failureCount++
			}
		}
	}

	// Summary
	fmt.Println(strings.Repeat("-", 50))
	fmt.Printf("Total: %d backups\n", len(backupFiles))
	fmt.Printf("[OK] Valid: %d\n", successCount)
	if failureCount > 0 {
		fmt.Printf("[FAIL] Failed: %d\n", failureCount)
		os.Exit(1)
	}

	return nil
}

// isCloudURI checks if a string is a cloud URI
func isCloudURI(s string) bool {
	return cloud.IsCloudURI(s)
}

// verifyCloudBackup downloads and verifies a backup from cloud storage
func verifyCloudBackup(ctx context.Context, uri string, quick, verbose bool) (*restore.DownloadResult, error) {
	// Download from cloud with checksum verification
	result, err := restore.DownloadFromCloudURI(ctx, uri, restore.DownloadOptions{
		VerifyChecksum: !quick, // Skip checksum if quick mode
		KeepLocal:      false,
	})
	if err != nil {
		return nil, err
	}

	// If not quick mode, also run full verification
	if !quick {
		_, err := verification.Verify(result.LocalPath)
		if err != nil {
			result.Cleanup()
			return nil, err
		}
	}

	return result, nil
}

// runVerifyCloudBackup verifies backups from cloud storage
func runVerifyCloudBackup(cmd *cobra.Command, args []string) error {
	fmt.Printf("Verifying cloud backup(s)...\n\n")

	successCount := 0
	failureCount := 0

	for _, uri := range args {
		if !isCloudURI(uri) {
			fmt.Printf("[WARN] Skipping non-cloud URI: %s\n", uri)
			continue
		}

		fmt.Printf("[CLOUD] %s\n", uri)

		// Download and verify
		result, err := verifyCloudBackup(cmd.Context(), uri, quickVerify, verboseVerify)
		if err != nil {
			fmt.Printf("   [FAIL] FAILED: %v\n\n", err)
			failureCount++
			continue
		}

		// Cleanup temp file
		defer result.Cleanup()

		fmt.Printf("   [OK] VALID\n")
		if verboseVerify && result.MetadataPath != "" {
			meta, _ := metadata.Load(result.MetadataPath)
			if meta != nil {
				fmt.Printf("   Size: %s\n", metadata.FormatSize(meta.SizeBytes))
				fmt.Printf("   SHA-256: %s\n", meta.SHA256)
				fmt.Printf("   Database: %s (%s)\n", meta.Database, meta.DatabaseType)
				fmt.Printf("   Created: %s\n", meta.Timestamp.Format(time.RFC3339))
			}
		}
		fmt.Println()
		successCount++
	}

	fmt.Printf("\n[OK] Summary: %d valid, %d failed\n", successCount, failureCount)

	if failureCount > 0 {
		os.Exit(1)
	}

	return nil
}
