// cmd/khimera-portable/main.go
package main

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"runtime"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/widget"

	"khimera/addressbook"
	"khimera/identity"
	"khimera/session"
	"khimera/transport"
)

// PortableApp represents the portable Khimera application
type PortableApp struct {
	config       *PortableConfig
	identity     *identity.Identity
	addressBook  *addressbook.AddressBook
	sessionMgr   *session.SessionManager
	transportMgr *transport.TransportManager
}

// PortableConfig holds portable mode configuration
type PortableConfig struct {
	IsPortable     bool
	BaseDir        string
	DataDir        string
	TorDir         string
	TempDir        string
	IdentityPath   string
	ContactsPath   string
	ConfigPath     string
	IsUSB          bool
	IsNetworkShare bool
	Platform       string
}

func main() {
	fmt.Println("╔════════════════════════════════════════╗")
	fmt.Println("║   KHIMERA PORTABLE v0.9                ║")
	fmt.Println("║   Privacy-First P2P Messenger          ║")
	fmt.Println("╚════════════════════════════════════════╝")
	fmt.Println()

	// Detect and setup portable mode
	config, err := detectPortableMode()
	if err != nil {
		log.Fatalf("Failed to initialize portable mode: %v", err)
	}

	// Display portable status
	displayPortableStatus(config)

	// Initialize portable app
	portableApp := &PortableApp{
		config: config,
	}

	// Setup data directories
	if err := portableApp.setupDirectories(); err != nil {
		log.Fatalf("Failed to setup directories: %v", err)
	}

	// Start GUI
	portableApp.startGUI()
}

// detectPortableMode detects portable environment
func detectPortableMode() (*PortableConfig, error) {
	// When running as AppImage, APPIMAGE env var points to the actual .AppImage file
	// os.Executable() would return the read-only mount path inside /tmp/.mount_*
	var baseDir string
	if appImagePath := os.Getenv("APPIMAGE"); appImagePath != "" {
		baseDir = filepath.Dir(appImagePath)
	} else {
		exe, err := os.Executable()
		if err != nil {
			return nil, fmt.Errorf("failed to get executable path: %w", err)
		}
		baseDir = filepath.Dir(exe)
	}

	config := &PortableConfig{
		IsPortable: true,
		BaseDir:    baseDir,
		DataDir:    filepath.Join(baseDir, "data"),
		TorDir:     filepath.Join(baseDir, "tor"),
		TempDir:    filepath.Join(baseDir, "temp"),
		Platform:   runtime.GOOS,
	}

	// Set file paths
	config.IdentityPath = filepath.Join(config.DataDir, "identity.enc")
	config.ContactsPath = filepath.Join(config.DataDir, "contacts.enc")
	config.ConfigPath = filepath.Join(config.DataDir, "config.json")

	// Detect if running from USB
	config.IsUSB = isRemovableDrive(baseDir)
	config.IsNetworkShare = isNetworkPath(baseDir)

	return config, nil
}

// isRemovableDrive checks if path is on removable media
func isRemovableDrive(path string) bool {
	switch runtime.GOOS {
	case "windows":
		return isWindowsRemovable(path)
	case "linux":
		return isLinuxRemovable(path)
	default:
		return false
	}
}

// isWindowsRemovable checks for Windows removable drives
func isWindowsRemovable(path string) bool {
	// Simplified check - in production use Windows API
	drive := filepath.VolumeName(path)
	// Check if drive letter is in typical USB range (E: to Z:)
	if len(drive) > 0 {
		letter := drive[0]
		return letter >= 'E' && letter <= 'Z'
	}
	return false
}

// isLinuxRemovable checks for Linux removable media
func isLinuxRemovable(path string) bool {
	// Check if path contains /media or /mnt (typical USB mount points)
	return filepath.HasPrefix(path, "/media") || 
	       filepath.HasPrefix(path, "/mnt")
}

// isNetworkPath checks if running from network share
func isNetworkPath(path string) bool {
	switch runtime.GOOS {
	case "windows":
		return filepath.HasPrefix(path, "\\\\")
	case "linux":
		// Check for NFS/SMB mounts (simplified)
		return false
	}
	return false
}

// displayPortableStatus shows portable mode information
func displayPortableStatus(config *PortableConfig) {
	fmt.Println("📁 Portable Mode Configuration")
	fmt.Println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
	fmt.Printf("   Platform:      %s\n", config.Platform)
	fmt.Printf("   Base Dir:      %s\n", config.BaseDir)
	fmt.Printf("   Data Dir:      %s\n", config.DataDir)
	fmt.Printf("   Running from:  ")

	if config.IsUSB {
		fmt.Println("USB Drive ✓")
	} else if config.IsNetworkShare {
		fmt.Println("Network Share ✓")
	} else {
		fmt.Println("Local Drive")
	}
	fmt.Println()
}

// setupDirectories creates required directories
func (pa *PortableApp) setupDirectories() error {
	dirs := []string{
		pa.config.DataDir,
		pa.config.TorDir,
		pa.config.TempDir,
	}

	for _, dir := range dirs {
		if err := os.MkdirAll(dir, 0700); err != nil {
			return fmt.Errorf("failed to create directory %s: %w", dir, err)
		}
	}

	fmt.Println("✓ Directories initialized")
	return nil
}

// startGUI launches the portable GUI application
func (pa *PortableApp) startGUI() {
	myApp := app.New()
	myWindow := myApp.NewWindow("Khimera Portable v0.9")

	// Welcome screen
	welcomeLabel := widget.NewLabel("Welcome to Khimera Portable")
	welcomeLabel.Alignment = fyne.TextAlignCenter

	infoLabel := widget.NewLabel(fmt.Sprintf(
		"Running from: %s\nData directory: %s",
		pa.config.BaseDir,
		pa.config.DataDir,
	))
	infoLabel.Wrapping = fyne.TextWrapWord

	// Identity section
	var passphraseEntry *widget.Entry
	var statusLabel *widget.Label

	statusLabel = widget.NewLabel("No identity loaded")

	passphraseEntry = widget.NewPasswordEntry()
	passphraseEntry.SetPlaceHolder("Enter passphrase...")

	// Load/Create identity button
	loadBtn := widget.NewButton("Load Identity", func() {
		passphrase := passphraseEntry.Text
		if passphrase == "" {
			statusLabel.SetText("⚠ Please enter a passphrase")
			return
		}

		// Try to load existing identity
		if _, err := os.Stat(pa.config.IdentityPath); err == nil {
			id, err := identity.LoadIdentity(pa.config.IdentityPath, []byte(passphrase))
			if err != nil {
				statusLabel.SetText("⚠ Failed to load identity (wrong passphrase?)")
				return
			}
			pa.identity = id
			statusLabel.SetText("✓ Identity loaded: " + id.GetPublicKeyHex()[:16] + "...")
		} else {
			// Create new identity
			id, err := identity.NewIdentity()
			if err != nil {
				statusLabel.SetText("⚠ Failed to create identity")
				return
			}

			if err := id.Save(pa.config.IdentityPath, []byte(passphrase)); err != nil {
				statusLabel.SetText("⚠ Failed to save identity")
				return
			}

			pa.identity = id
			statusLabel.SetText("✓ New identity created: " + id.GetPublicKeyHex()[:16] + "...")
		}

		// Initialize other components
		pa.initializeComponents()
	})

	// Quit button
	quitBtn := widget.NewButton("Quit", func() {
		pa.cleanup()
		myApp.Quit()
	})

	// Layout
	content := container.NewVBox(
		welcomeLabel,
		widget.NewSeparator(),
		infoLabel,
		widget.NewSeparator(),
		widget.NewLabel("Identity Management:"),
		passphraseEntry,
		loadBtn,
		statusLabel,
		widget.NewSeparator(),
		quitBtn,
	)

	myWindow.SetContent(content)
	myWindow.Resize(fyne.NewSize(600, 400))
	myWindow.CenterOnScreen()
	myWindow.ShowAndRun()
}

// initializeComponents initializes core components after identity is loaded
func (pa *PortableApp) initializeComponents() error {
	// Initialize session manager
	pa.sessionMgr = session.NewSessionManager()

	// Initialize transport manager
	pa.transportMgr = transport.NewTransportManager()

	// Try to load address book
	if _, err := os.Stat(pa.config.ContactsPath); err == nil {
		// Load existing contacts
		fmt.Println("✓ Address book loaded")
	} else {
		// Create new address book
		pa.addressBook = addressbook.NewAddressBook()
		fmt.Println("✓ New address book created")
	}

	fmt.Println("✓ Components initialized")
	return nil
}

// cleanup performs cleanup on application exit
func (pa *PortableApp) cleanup() {
	fmt.Println("\n🧹 Cleaning up...")

	// Secure wipe sessions
	if pa.sessionMgr != nil {
		pa.sessionMgr.SecureWipeAll()
		fmt.Println("   ✓ Sessions wiped")
	}

	// Close transports
	if pa.transportMgr != nil {
		pa.transportMgr.Close()
		fmt.Println("   ✓ Transports closed")
	}

	// Wipe identity from memory
	if pa.identity != nil {
		pa.identity.SecureWipe()
		fmt.Println("   ✓ Identity wiped from memory")
	}

	// Clean temp directory
	if pa.config.TempDir != "" {
		os.RemoveAll(pa.config.TempDir)
		fmt.Println("   ✓ Temp files removed")
	}

	fmt.Println("✓ Cleanup complete")
}
