// Package catalog provides backup catalog management with SQLite storage
package catalog

import (
	"context"
	"fmt"
	"time"
)

// Entry represents a single backup in the catalog
type Entry struct {
	ID              int64             `json:"id"`
	Database        string            `json:"database"`
	DatabaseType    string            `json:"database_type"` // postgresql, mysql, mariadb
	Host            string            `json:"host"`
	Port            int               `json:"port"`
	BackupPath      string            `json:"backup_path"`
	BackupType      string            `json:"backup_type"` // full, incremental
	SizeBytes       int64             `json:"size_bytes"`
	SHA256          string            `json:"sha256"`
	Compression     string            `json:"compression"`
	Encrypted       bool              `json:"encrypted"`
	CreatedAt       time.Time         `json:"created_at"`
	Duration        float64           `json:"duration_seconds"`
	Status          BackupStatus      `json:"status"`
	VerifiedAt      *time.Time        `json:"verified_at,omitempty"`
	VerifyValid     *bool             `json:"verify_valid,omitempty"`
	DrillTestedAt   *time.Time        `json:"drill_tested_at,omitempty"`
	DrillSuccess    *bool             `json:"drill_success,omitempty"`
	CloudLocation   string            `json:"cloud_location,omitempty"`
	RetentionPolicy string            `json:"retention_policy,omitempty"` // daily, weekly, monthly, yearly
	Tags            map[string]string `json:"tags,omitempty"`
	Metadata        map[string]string `json:"metadata,omitempty"`
	RestoreInfo     *RestoreInfo      `json:"restore_info,omitempty"` // Info about restore operations
	Path            string            `json:"path,omitempty"`         // Alias for BackupPath
}

// RestoreInfo contains information about a restore operation
type RestoreInfo struct {
	Success      bool          `json:"success"`
	CompletedAt  time.Time     `json:"completed_at"`
	Duration     time.Duration `json:"duration"`
	ParallelJobs int           `json:"parallel_jobs"`
	Profile      string        `json:"profile"`
	TargetDB     string        `json:"target_db,omitempty"`
	ErrorMessage string        `json:"error_message,omitempty"`
}

// BackupStatus represents the state of a backup
type BackupStatus string

const (
	StatusCompleted BackupStatus = "completed"
	StatusFailed    BackupStatus = "failed"
	StatusVerified  BackupStatus = "verified"
	StatusCorrupted BackupStatus = "corrupted"
	StatusDeleted   BackupStatus = "deleted"
	StatusArchived  BackupStatus = "archived"
)

// Gap represents a detected backup gap
type Gap struct {
	Database    string        `json:"database"`
	GapStart    time.Time     `json:"gap_start"`
	GapEnd      time.Time     `json:"gap_end"`
	Duration    time.Duration `json:"duration"`
	ExpectedAt  time.Time     `json:"expected_at"`
	Description string        `json:"description"`
	Severity    GapSeverity   `json:"severity"`
}

// GapSeverity indicates how serious a backup gap is
type GapSeverity string

const (
	SeverityInfo     GapSeverity = "info"     // Gap within tolerance
	SeverityWarning  GapSeverity = "warning"  // Gap exceeds expected interval
	SeverityCritical GapSeverity = "critical" // Gap exceeds RPO
)

// Stats contains backup statistics
type Stats struct {
	TotalBackups     int64            `json:"total_backups"`
	TotalSize        int64            `json:"total_size_bytes"`
	TotalSizeHuman   string           `json:"total_size_human"`
	OldestBackup     *time.Time       `json:"oldest_backup,omitempty"`
	NewestBackup     *time.Time       `json:"newest_backup,omitempty"`
	ByDatabase       map[string]int64 `json:"by_database"`
	ByType           map[string]int64 `json:"by_type"`
	ByStatus         map[string]int64 `json:"by_status"`
	VerifiedCount    int64            `json:"verified_count"`
	DrillTestedCount int64            `json:"drill_tested_count"`
	AvgDuration      float64          `json:"avg_duration_seconds"`
	AvgSize          int64            `json:"avg_size_bytes"`
	GapsDetected     int              `json:"gaps_detected"`
}

// SearchQuery represents search criteria for catalog entries
type SearchQuery struct {
	Database     string     // Filter by database name (supports wildcards)
	DatabaseType string     // Filter by database type
	Host         string     // Filter by host
	Status       string     // Filter by status
	StartDate    *time.Time // Backups after this date
	EndDate      *time.Time // Backups before this date
	MinSize      int64      // Minimum size in bytes
	MaxSize      int64      // Maximum size in bytes
	BackupType   string     // full, incremental
	Encrypted    *bool      // Filter by encryption status
	Verified     *bool      // Filter by verification status
	DrillTested  *bool      // Filter by drill test status
	Limit        int        // Max results (0 = no limit)
	Offset       int        // Offset for pagination
	OrderBy      string     // Field to order by
	OrderDesc    bool       // Order descending
}

// GapDetectionConfig configures gap detection
type GapDetectionConfig struct {
	ExpectedInterval time.Duration // Expected backup interval (e.g., 24h)
	Tolerance        time.Duration // Allowed variance (e.g., 1h)
	RPOThreshold     time.Duration // Critical threshold (RPO)
	StartDate        *time.Time    // Start of analysis window
	EndDate          *time.Time    // End of analysis window
}

// Catalog defines the interface for backup catalog operations
type Catalog interface {
	// Entry management
	Add(ctx context.Context, entry *Entry) error
	Update(ctx context.Context, entry *Entry) error
	Delete(ctx context.Context, id int64) error
	Get(ctx context.Context, id int64) (*Entry, error)
	GetByPath(ctx context.Context, path string) (*Entry, error)

	// Search and listing
	Search(ctx context.Context, query *SearchQuery) ([]*Entry, error)
	List(ctx context.Context, database string, limit int) ([]*Entry, error)
	ListDatabases(ctx context.Context) ([]string, error)
	Count(ctx context.Context, query *SearchQuery) (int64, error)

	// Statistics
	Stats(ctx context.Context) (*Stats, error)
	StatsByDatabase(ctx context.Context, database string) (*Stats, error)

	// Gap detection
	DetectGaps(ctx context.Context, database string, config *GapDetectionConfig) ([]*Gap, error)
	DetectAllGaps(ctx context.Context, config *GapDetectionConfig) (map[string][]*Gap, error)

	// Verification tracking
	MarkVerified(ctx context.Context, id int64, valid bool) error
	MarkDrillTested(ctx context.Context, id int64, success bool) error

	// Sync with filesystem
	SyncFromDirectory(ctx context.Context, dir string) (*SyncResult, error)
	SyncFromCloud(ctx context.Context, provider, bucket, prefix string) (*SyncResult, error)

	// Maintenance
	Prune(ctx context.Context, before time.Time) (int, error)
	Vacuum(ctx context.Context) error
	Close() error
}

// SyncResult contains results from a catalog sync operation
type SyncResult struct {
	Added         int      `json:"added"`
	Updated       int      `json:"updated"`
	Removed       int      `json:"removed"`
	Skipped       int      `json:"skipped"` // Files without metadata (legacy backups)
	Errors        int      `json:"errors"`
	Duration      float64  `json:"duration_seconds"`
	Details       []string `json:"details,omitempty"`
	LegacyWarning string   `json:"legacy_warning,omitempty"` // Warning about legacy files
}

// FormatSize formats bytes as human-readable string
func FormatSize(bytes int64) string {
	const unit = 1024
	if bytes < unit {
		return fmt.Sprintf("%d B", bytes)
	}
	div, exp := int64(unit), 0
	for n := bytes / unit; n >= unit; n /= unit {
		div *= unit
		exp++
	}
	return fmt.Sprintf("%.1f %cB", float64(bytes)/float64(div), "KMGTPE"[exp])
}

// FormatDuration formats duration as human-readable string
func FormatDuration(d time.Duration) string {
	if d < time.Minute {
		return fmt.Sprintf("%.0fs", d.Seconds())
	}
	if d < time.Hour {
		mins := int(d.Minutes())
		secs := int(d.Seconds()) - mins*60
		return fmt.Sprintf("%dm %ds", mins, secs)
	}
	hours := int(d.Hours())
	mins := int(d.Minutes()) - hours*60
	return fmt.Sprintf("%dh %dm", hours, mins)
}
