package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"strconv"
	"strings"
	"syscall"
	"time"
)

var DebugMode bool

const (
	VERSION    = "1.0.0"
	PIDFILE    = "techircd.pid"
	CONFIGFILE = "config.json"
)

func main() {
	// Parse command line arguments
	if len(os.Args) < 2 {
		showUsage()
		os.Exit(1)
	}

	command := strings.ToLower(os.Args[1])

	// Parse flags for the remaining arguments
	flagSet := flag.NewFlagSet("techircd", flag.ExitOnError)
	configFile := flagSet.String("config", CONFIGFILE, "Path to configuration file")
	daemon := flagSet.Bool("daemon", false, "Run as daemon (background)")
	verbose := flagSet.Bool("verbose", false, "Enable verbose logging")
	debug := flagSet.Bool("debug", false, "Enable extremely detailed debug logging (shows all IRC messages)")
	port := flagSet.Int("port", 0, "Override port from config")

	// Parse remaining arguments
	flagSet.Parse(os.Args[2:])

	switch command {
	case "start":
		startServer(*configFile, *daemon, *verbose, *debug, *port)
	case "stop":
		stopServer()
	case "restart":
		stopServer()
		time.Sleep(2 * time.Second)
		startServer(*configFile, *daemon, *verbose, *debug, *port)
	case "status":
		showStatus()
	case "reload":
		reloadConfig()
	case "version", "-v", "--version":
		fmt.Printf("TechIRCd version %s\n", VERSION)
	case "help", "-h", "--help":
		showUsage()
	default:
		fmt.Printf("Unknown command: %s\n", command)
		showUsage()
		os.Exit(1)
	}
}

func showUsage() {
	fmt.Printf(`TechIRCd %s - Modern IRC Server

Usage: %s <command> [options]

Commands:
  start       Start the IRC server
  stop        Stop the IRC server
  restart     Restart the IRC server
  status      Show server status
  reload      Reload configuration
  version     Show version information
  help        Show this help message

Options:
  -config <file>    Path to configuration file (default: config.json)
  -daemon           Run as daemon (background process)
  -verbose          Enable verbose logging
  -debug            Enable extremely detailed debug logging (shows all IRC messages)
  -port <port>      Override port from configuration

Examples:
  %s start                    # Start with default config
  %s start -config custom.json # Start with custom config
  %s start -daemon            # Start as background daemon
  %s stop                     # Stop the server
  %s status                   # Check if server is running

`, VERSION, os.Args[0], os.Args[0], os.Args[0], os.Args[0], os.Args[0], os.Args[0])
}

func startServer(configFile string, daemon, verbose, debug bool, port int) {
	// Check if server is already running
	if isRunning() {
		fmt.Println("TechIRCd is already running")
		os.Exit(1)
	}

	// Load configuration
	config, err := LoadConfig(configFile)
	if err != nil {
		log.Printf("Failed to load config from %s, using defaults: %v", configFile, err)
		config = DefaultConfig()
		if err := SaveConfig(config, configFile); err != nil {
			log.Printf("Failed to save default config: %v", err)
		}
	}

	// Override port if specified
	if port > 0 {
		config.Server.Listen.Port = port
		fmt.Printf("Port overridden to %d\n", port)
	}

	// Validate configuration
	if err := config.Validate(); err != nil {
		log.Fatalf("Configuration validation failed: %v", err)
	}
	config.SanitizeConfig()

	if verbose {
		log.Println("Configuration validated successfully")
	}
	
	// Set global debug mode
	DebugMode = debug
	if debug {
		log.Println("Debug mode enabled - will log all IRC messages")
	}

	// Start as daemon if requested
	if daemon {
		startDaemon(configFile, verbose, debug, port)
		return
	}

	// Write PID file
	if err := writePidFile(); err != nil {
		log.Fatalf("Failed to write PID file: %v", err)
	}
	defer removePidFile()

	// Create server
	server := NewServer(config)

	// Setup signal handling for graceful shutdown with forced shutdown capability
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP)

	shutdownInProgress := false
	go func() {
		for sig := range c {
			switch sig {
			case syscall.SIGHUP:
				log.Println("Received SIGHUP, reloading configuration...")
				// Reload config here if needed
			case os.Interrupt, syscall.SIGTERM:
				if shutdownInProgress {
					log.Println("Received second interrupt signal, forcing immediate shutdown...")
					removePidFile()
					os.Exit(1) // Force exit
				}
				
				shutdownInProgress = true
				log.Println("Shutting down server...")
				
				// Start shutdown with timeout
				shutdownComplete := make(chan bool, 1)
				go func() {
					defer func() {
						if r := recover(); r != nil {
							log.Printf("Panic during shutdown: %v", r)
						}
						shutdownComplete <- true
					}()
					server.Shutdown()
				}()
				
				// Wait for graceful shutdown or force after timeout
				select {
				case <-shutdownComplete:
					log.Println("Graceful shutdown completed")
				case <-time.After(10 * time.Second):
					log.Println("Shutdown timeout reached, forcing exit...")
				}
				
				removePidFile()
				os.Exit(0)
			}
		}
	}()

	// Start the server
	fmt.Printf("Starting TechIRCd %s on %s:%d\n", VERSION, config.Server.Listen.Host, config.Server.Listen.Port)
	if config.Server.Listen.EnableSSL {
		fmt.Printf("SSL enabled on port %d\n", config.Server.Listen.SSLPort)
	}

	if err := server.Start(); err != nil {
		log.Fatalf("Failed to start server: %v", err)
	}
}

func startDaemon(configFile string, verbose, debug bool, port int) {
	// Build command arguments
	args := []string{os.Args[0], "start", "-config", configFile}
	if verbose {
		args = append(args, "-verbose")
	}
	if debug {
		args = append(args, "-debug")
	}
	if port > 0 {
		args = append(args, "-port", strconv.Itoa(port))
	}

	// Start as background process
	cmd := exec.Command(args[0], args[1:]...)
	cmd.Stdout = nil
	cmd.Stderr = nil
	cmd.Stdin = nil

	if err := cmd.Start(); err != nil {
		log.Fatalf("Failed to start daemon: %v", err)
	}

	fmt.Printf("TechIRCd started as daemon (PID: %d)\n", cmd.Process.Pid)
}

func stopServer() {
	pid, err := readPidFile()
	if err != nil {
		fmt.Println("TechIRCd is not running")
		return
	}

	process, err := os.FindProcess(pid)
	if err != nil {
		fmt.Println("TechIRCd is not running")
		removePidFile()
		return
	}

	// Send SIGTERM for graceful shutdown
	if err := process.Signal(syscall.SIGTERM); err != nil {
		fmt.Println("TechIRCd is not running")
		removePidFile()
		return
	}

	// Wait for process to stop
	for i := 0; i < 10; i++ {
		if !isRunning() {
			fmt.Println("TechIRCd stopped")
			return
		}
		time.Sleep(500 * time.Millisecond)
	}

	// Force kill if still running
	process.Signal(syscall.SIGKILL)
	fmt.Println("TechIRCd force stopped")
	removePidFile()
}

func showStatus() {
	if isRunning() {
		pid, _ := readPidFile()
		fmt.Printf("TechIRCd is running (PID: %d)\n", pid)
	} else {
		fmt.Println("TechIRCd is not running")
	}
}

func reloadConfig() {
	pid, err := readPidFile()
	if err != nil {
		fmt.Println("TechIRCd is not running")
		return
	}

	process, err := os.FindProcess(pid)
	if err != nil {
		fmt.Println("TechIRCd is not running")
		return
	}

	if err := process.Signal(syscall.SIGHUP); err != nil {
		fmt.Println("Failed to reload configuration")
		return
	}

	fmt.Println("Configuration reload signal sent")
}

func isRunning() bool {
	pid, err := readPidFile()
	if err != nil {
		return false
	}

	process, err := os.FindProcess(pid)
	if err != nil {
		return false
	}

	// Send signal 0 to check if process exists
	err = process.Signal(syscall.Signal(0))
	return err == nil
}

func writePidFile() error {
	pid := os.Getpid()
	return os.WriteFile(PIDFILE, []byte(strconv.Itoa(pid)), 0644)
}

func readPidFile() (int, error) {
	data, err := os.ReadFile(PIDFILE)
	if err != nil {
		return 0, err
	}
	return strconv.Atoi(strings.TrimSpace(string(data)))
}

func removePidFile() {
	os.Remove(PIDFILE)
}
