package main

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

	"github.com/linuxdeepin/go-rofs-err-watcher/pkg/client"
)

var (
	optHelp    bool
	optEnable  bool
	optDisable bool
	optStatus  bool
	optVerbose bool
)

func init() {
	flag.BoolVar(&optHelp, "h", false, "show help message and exit")
	flag.BoolVar(&optEnable, "enable", false, "enable error notification")
	flag.BoolVar(&optDisable, "disable", false, "disable error notification")
	flag.BoolVar(&optStatus, "status", false, "query error notification status")
	flag.BoolVar(&optVerbose, "verbose", false, "print detailed notification information")
}

func showHelp() {
	fmt.Println("Usage: go-rofs-err-watcher [OPTIONS]")
	fmt.Println("Monitor read-only filesystem error messages from the /usr directory.")
	fmt.Println()
	fmt.Println("OPTIONS:")
	fmt.Println("  -h             Show this help message and exit")
	fmt.Println("  -enable        Enable error notification via netlink")
	fmt.Println("  -disable       Disable error notification via netlink")
	fmt.Println("  -status        Query error notification status")
	fmt.Println("  -verbose       Print detailed notification information")
	fmt.Println()
	fmt.Println("EXAMPLES:")
	fmt.Println("  # Enable error notification")
	fmt.Println("  sudo go-rofs-err-watcher -enable")
	fmt.Println()
	fmt.Println("  # Check status")
	fmt.Println("  go-rofs-err-watcher -status")
	fmt.Println()
	fmt.Println("  # Start monitoring (default behavior)")
	fmt.Println("  go-rofs-err-watcher")
}

// printNotification prints a formatted notification message with all available fields
func printNotification(msg client.NotificationMessage) {
	// Print file information
	if len(msg.Filenames) > 0 {
		if len(msg.Filenames) == 1 {
			fmt.Printf("  File: %s", msg.Filenames[0])
			if len(msg.Inodes) > 0 {
				fmt.Printf(" (inode: %d)", msg.Inodes[0])
			}
			fmt.Println()
		} else {
			fmt.Printf("  Files (%d):\n", len(msg.Filenames))
			for i, filename := range msg.Filenames {
				fmt.Printf("    - %s", filename)
				if i < len(msg.Inodes) {
					fmt.Printf(" (inode: %d)", msg.Inodes[i])
				}
				fmt.Println()
			}
		}
	}

	// Print process information
	if msg.PID != 0 {
		fmt.Printf("  PID: %d\n", msg.PID)
	}
	if msg.PPID != 0 {
		fmt.Printf("  PPID: %d\n", msg.PPID)
	}
	if msg.UID != 0 {
		fmt.Printf("  UID: %d\n", msg.UID)
	}
	if msg.GID != 0 {
		fmt.Printf("  GID: %d\n", msg.GID)
	}
	if msg.Comm != "" {
		fmt.Printf("  Comm: %s\n", msg.Comm)
	}

	fmt.Println()
}

func main() {
	flag.Parse()
	if optHelp {
		showHelp()
		os.Exit(0)
	}
	client.OptVerbose = optVerbose

	// Handle control commands (enable, disable, status)
	if optEnable || optDisable || optStatus {
		handleControlCommand()
		return
	}

	// Default behavior: monitor notifications
	monitorNotifications()
}

// handleControlCommand handles enable, disable, and status commands
func handleControlCommand() {
	// Create a simple client (no monitoring)
	c, err := client.NewClient()
	if err != nil {
		log.Fatalf("Failed to create client: %v", err)
	}
	defer c.Close()

	if optEnable {
		if err := c.Enable(); err != nil {
			log.Fatalf("Failed to enable error notification: %v", err)
		}
		fmt.Println("Error notification enabled successfully")
	}

	if optDisable {
		if err := c.Disable(); err != nil {
			log.Fatalf("Failed to disable error notification: %v", err)
		}
		fmt.Println("Error notification disabled successfully")
	}

	if optStatus {
		enabled, err := c.GetStatus()
		if err != nil {
			log.Fatalf("Failed to get error notification status: %v", err)
		}
		if enabled {
			fmt.Println("Error notification is: ENABLED")
		} else {
			fmt.Println("Error notification is: DISABLED")
		}
	}
}

// monitorNotifications starts monitoring error notifications
func monitorNotifications() {
	// Create monitoring client (automatically enables notification and joins multicast group)
	c, err := client.NewClientForMonitoring()
	if err != nil {
		log.Fatalf("Failed to create monitoring client: %v", err)
	}
	defer c.Close()

	// Get and display connection information
	familyName, familyID, groupID := c.GetFamilyInfo()
	fmt.Printf("Found family '%s' with ID: %d\n", familyName, familyID)
	fmt.Printf("Found multicast group with ID: %d\n", groupID)
	fmt.Println("Joined multicast group successfully")
	fmt.Println("Error notification enabled")
	fmt.Println("Waiting for notifications...")

	// Setup signal handling
	ctx, cancel := context.WithCancel(context.Background())
	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
	go func() {
		<-sigCh
		fmt.Println("\nReceived signal, shutting down...")
		cancel()
	}()

	// Receive message
	msgCh, errCh := c.ReceiveMessages(ctx)

	for {
		select {
		case <-ctx.Done():
			fmt.Println("Monitoring stopped.")
			return
		case err := <-errCh:
			if err != nil {
				log.Printf("Error: %v", err)
			}
		case msg, ok := <-msgCh:
			if !ok {
				fmt.Println("Message channel closed.")
				return
			}

			// Print message information
			printNotification(msg)
		}
	}
}
