// Package security - Emergency wipe system for military/capture scenarios
package security

import (
	"crypto/rand"
	"fmt"
	"os"
	"path/filepath"
	"sync"
	"time"
)

// EmergencyWipe handles secure data destruction
// Critical for military scenarios if device is captured
type EmergencyWipe struct {
	dataDir      string
	identityPath string
	contactsPath string
	queueDir     string
	tempDir      string
	wiping       bool
	mu           sync.Mutex
	onWipeStart  func()
	onWipeComplete func()
}

// WipeConfig holds emergency wipe configuration
type WipeConfig struct {
	DataDir      string // Main data directory
	IdentityPath string // Identity file path
	ContactsPath string // Contacts file path
	QueueDir     string // Message queue directory
	TempDir      string // Temp files directory
	Passes       int    // Number of overwrite passes (DOD 5220.22-M uses 7)
}

// NewEmergencyWipe creates a new emergency wipe system
func NewEmergencyWipe(config *WipeConfig) *EmergencyWipe {
	if config == nil {
		config = &WipeConfig{
			Passes: 7, // DOD standard
		}
	}

	return &EmergencyWipe{
		dataDir:      config.DataDir,
		identityPath: config.IdentityPath,
		contactsPath: config.ContactsPath,
		queueDir:     config.QueueDir,
		tempDir:      config.TempDir,
	}
}

// Wipe performs emergency data destruction
func (ew *EmergencyWipe) Wipe() error {
	ew.mu.Lock()
	if ew.wiping {
		ew.mu.Unlock()
		return fmt.Errorf("wipe already in progress")
	}
	ew.wiping = true
	ew.mu.Unlock()

	defer func() {
		ew.mu.Lock()
		ew.wiping = false
		ew.mu.Unlock()
	}()

	fmt.Println("\n🚨 EMERGENCY WIPE INITIATED 🚨")
	fmt.Println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")

	if ew.onWipeStart != nil {
		ew.onWipeStart()
	}

	// Step 1: Wipe identity file
	if ew.identityPath != "" {
		fmt.Printf("🔥 Wiping identity: %s\n", ew.identityPath)
		if err := ew.secureWipeFile(ew.identityPath, 7); err != nil {
			fmt.Printf("⚠️  Warning: %v\n", err)
		} else {
			fmt.Println("✓ Identity wiped")
		}
	}

	// Step 2: Wipe contacts file
	if ew.contactsPath != "" {
		fmt.Printf("🔥 Wiping contacts: %s\n", ew.contactsPath)
		if err := ew.secureWipeFile(ew.contactsPath, 7); err != nil {
			fmt.Printf("⚠️  Warning: %v\n", err)
		} else {
			fmt.Println("✓ Contacts wiped")
		}
	}

	// Step 3: Wipe message queue
	if ew.queueDir != "" {
		fmt.Printf("🔥 Wiping message queue: %s\n", ew.queueDir)
		if err := ew.secureWipeDirectory(ew.queueDir); err != nil {
			fmt.Printf("⚠️  Warning: %v\n", err)
		} else {
			fmt.Println("✓ Message queue wiped")
		}
	}

	// Step 4: Wipe temp files
	if ew.tempDir != "" {
		fmt.Printf("🔥 Wiping temp files: %s\n", ew.tempDir)
		if err := ew.secureWipeDirectory(ew.tempDir); err != nil {
			fmt.Printf("⚠️  Warning: %v\n", err)
		} else {
			fmt.Println("✓ Temp files wiped")
		}
	}

	// Step 5: Wipe entire data directory
	if ew.dataDir != "" {
		fmt.Printf("🔥 Wiping data directory: %s\n", ew.dataDir)
		if err := ew.secureWipeDirectory(ew.dataDir); err != nil {
			fmt.Printf("⚠️  Warning: %v\n", err)
		} else {
			fmt.Println("✓ Data directory wiped")
		}
	}

	fmt.Println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
	fmt.Println("✅ EMERGENCY WIPE COMPLETE")
	fmt.Println("All sensitive data has been securely destroyed.")
	fmt.Println("")

	if ew.onWipeComplete != nil {
		ew.onWipeComplete()
	}

	return nil
}

// secureWipeFile overwrites a file multiple times before deletion
// Implements DOD 5220.22-M standard (7-pass wipe)
func (ew *EmergencyWipe) secureWipeFile(path string, passes int) error {
	// Check if file exists
	info, err := os.Stat(path)
	if err != nil {
		if os.IsNotExist(err) {
			return nil // File doesn't exist - nothing to wipe
		}
		return fmt.Errorf("stat failed: %w", err)
	}

	size := info.Size()

	// Open file for writing
	file, err := os.OpenFile(path, os.O_WRONLY, 0)
	if err != nil {
		return fmt.Errorf("open failed: %w", err)
	}
	defer file.Close()

	// Perform multiple overwrite passes
	for pass := 1; pass <= passes; pass++ {
		// Seek to beginning
		file.Seek(0, 0)

		// Overwrite with different patterns
		var pattern []byte
		switch pass % 3 {
		case 0:
			// All zeros
			pattern = make([]byte, size)
		case 1:
			// All ones
			pattern = make([]byte, size)
			for i := range pattern {
				pattern[i] = 0xFF
			}
		case 2:
			// Random data
			pattern = make([]byte, size)
			rand.Read(pattern)
		}

		if _, err := file.Write(pattern); err != nil {
			return fmt.Errorf("write pass %d failed: %w", pass, err)
		}

		// Sync to disk
		file.Sync()
	}

	file.Close()

	// Delete the file
	if err := os.Remove(path); err != nil {
		return fmt.Errorf("delete failed: %w", err)
	}

	return nil
}

// secureWipeDirectory recursively wipes all files in a directory
func (ew *EmergencyWipe) secureWipeDirectory(dir string) error {
	// Walk directory tree
	return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return nil // Skip errors
		}

		// Skip directories (will be removed after contents wiped)
		if info.IsDir() {
			return nil
		}

		// Wipe file
		if err := ew.secureWipeFile(path, 7); err != nil {
			fmt.Printf("⚠️  Failed to wipe %s: %v\n", path, err)
		}

		return nil
	})

	// Remove empty directory
	// os.RemoveAll(dir) // Uncomment to also delete directory structure
}

// QuickWipe performs a fast single-pass wipe (for time-critical scenarios)
func (ew *EmergencyWipe) QuickWipe() error {
	fmt.Println("\n⚡ QUICK WIPE INITIATED (Single-pass)")
	fmt.Println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")

	// Single-pass wipe of critical files
	if ew.identityPath != "" {
		ew.secureWipeFile(ew.identityPath, 1)
	}
	if ew.contactsPath != "" {
		ew.secureWipeFile(ew.contactsPath, 1)
	}

	fmt.Println("✅ QUICK WIPE COMPLETE (1 pass)")
	return nil
}

// SetOnWipeStart sets callback for when wipe starts
func (ew *EmergencyWipe) SetOnWipeStart(callback func()) {
	ew.mu.Lock()
	defer ew.mu.Unlock()
	ew.onWipeStart = callback
}

// SetOnWipeComplete sets callback for when wipe completes
func (ew *EmergencyWipe) SetOnWipeComplete(callback func()) {
	ew.mu.Lock()
	defer ew.mu.Unlock()
	ew.onWipeComplete = callback
}

// IsWiping returns whether wipe is in progress
func (ew *EmergencyWipe) IsWiping() bool {
	ew.mu.Lock()
	defer ew.mu.Unlock()
	return ew.wiping
}

// PanicButton is a simple wrapper for emergency wipe
func PanicButton(config *WipeConfig) {
	fmt.Println("\n╔════════════════════════════════════════════════╗")
	fmt.Println("║        🚨 PANIC BUTTON ACTIVATED 🚨           ║")
	fmt.Println("╚════════════════════════════════════════════════╝")
	fmt.Println("")

	wipe := NewEmergencyWipe(config)
	wipe.Wipe()

	fmt.Println("Press any key to exit...")
	fmt.Scanln()
	os.Exit(0)
}

// String returns a string representation
func (ew *EmergencyWipe) String() string {
	ew.mu.Lock()
	defer ew.mu.Unlock()

	status := "ready"
	if ew.wiping {
		status = "WIPING"
	}

	return fmt.Sprintf("EmergencyWipe(status=%s, targets=[identity,contacts,queue,temp,data])",
		status)
}

// DeadMansSwitch implements auto-wipe if no activity detected
type DeadMansSwitch struct {
	timeout   time.Duration
	timer     *time.Timer
	mu        sync.Mutex
	active    bool
	onTrigger func()
}

// NewDeadMansSwitch creates a new dead man's switch
func NewDeadMansSwitch(timeout time.Duration, onTrigger func()) *DeadMansSwitch {
	dms := &DeadMansSwitch{
		timeout:   timeout,
		onTrigger: onTrigger,
	}
	return dms
}

// Start starts the dead man's switch
func (dms *DeadMansSwitch) Start() {
	dms.mu.Lock()
	defer dms.mu.Unlock()

	if dms.active {
		return
	}

	dms.active = true
	dms.timer = time.AfterFunc(dms.timeout, func() {
		fmt.Println("\n⏰ DEAD MAN'S SWITCH TRIGGERED")
		fmt.Println("No activity detected - initiating emergency wipe")
		if dms.onTrigger != nil {
			dms.onTrigger()
		}
	})
}

// Reset resets the dead man's switch timer
func (dms *DeadMansSwitch) Reset() {
	dms.mu.Lock()
	defer dms.mu.Unlock()

	if dms.timer != nil {
		dms.timer.Reset(dms.timeout)
	}
}

// Stop stops the dead man's switch
func (dms *DeadMansSwitch) Stop() {
	dms.mu.Lock()
	defer dms.mu.Unlock()

	if dms.timer != nil {
		dms.timer.Stop()
		dms.timer = nil
	}
	dms.active = false
}
