package cmd

import (
	"fmt"
	"strconv"
	"strings"
	"time"

	"port-knocker/internal"

	"github.com/gin-gonic/gin"
)

// setupKnockRoutes настраивает роуты для выполнения port knocking
func setupKnockRoutes(api *gin.RouterGroup) {
	// Execute: вход inline или YAML конфиг
	api.POST("/execute", func(c *gin.Context) {
		var req struct {
			Targets        string `json:"targets"`
			Delay          string `json:"delay"`
			Verbose        bool   `json:"verbose"`
			WaitConnection bool   `json:"waitConnection"`
			Gateway        string `json:"gateway"`
			ConfigYaml     string `json:"config_yaml"`
		}
		if err := c.BindJSON(&req); err != nil {
			c.JSON(400, gin.H{"error": fmt.Sprintf("bad json: %v", err)})
			return
		}

		knocker := internal.NewPortKnocker()

		// Определяем режим: inline или YAML
		if strings.TrimSpace(req.ConfigYaml) != "" {
			// YAML режим - загружаем конфигурацию из строки
			config, err := internal.LoadConfigFromString(req.ConfigYaml)
			if err != nil {
				c.JSON(400, gin.H{"error": fmt.Sprintf("invalid yaml: %v", err)})
				return
			}

			// Применяем дополнительные параметры из запроса
			if req.Gateway != "" {
				for i := range config.Targets {
					config.Targets[i].Gateway = req.Gateway
				}
			}

			if err := knocker.ExecuteWithConfig(config, req.Verbose, req.WaitConnection); err != nil {
				c.JSON(400, gin.H{"error": err.Error()})
				return
			}
			c.JSON(200, gin.H{"status": "ok"})
			return
		} else {
			// Inline режим
			if strings.TrimSpace(req.Targets) == "" {
				c.JSON(400, gin.H{"error": "targets is required in inline mode"})
				return
			}
			config, err := parseInlineTargetsWithWait(req.Targets, req.Delay, req.WaitConnection)
			if err != nil {
				c.JSON(400, gin.H{"error": fmt.Sprintf("invalid targets: %v", err)})
				return
			}

			// Применяем gateway к каждой цели
			if req.Gateway != "" {
				for i := range config.Targets {
					config.Targets[i].Gateway = req.Gateway
				}
			}

			if err := knocker.ExecuteWithConfig(&config, req.Verbose, req.WaitConnection); err != nil {
				c.JSON(400, gin.H{"error": err.Error()})
				return
			}
			c.JSON(200, gin.H{"status": "ok"})
		}
	})
}

// parseInlineTargetsWithWait парсит inline строку целей в Config с поддержкой waitConnection
func parseInlineTargetsWithWait(targets, delay string, waitConnection bool) (internal.Config, error) {
	var config internal.Config

	// Парсим targets
	targetStrings := strings.Split(targets, ";")
	for _, targetStr := range targetStrings {
		targetStr = strings.TrimSpace(targetStr)
		if targetStr == "" {
			continue
		}

		parts := strings.Split(targetStr, ":")
		if len(parts) != 3 {
			return config, fmt.Errorf("invalid target format: %s (expected protocol:host:port)", targetStr)
		}

		protocol := strings.TrimSpace(parts[0])
		host := strings.TrimSpace(parts[1])
		portStr := strings.TrimSpace(parts[2])

		if protocol != "tcp" && protocol != "udp" {
			return config, fmt.Errorf("unsupported protocol: %s (only tcp/udp supported)", protocol)
		}

		port, err := strconv.Atoi(portStr)
		if err != nil {
			return config, fmt.Errorf("invalid port: %s", portStr)
		}

		// Парсим delay
		var targetDelay internal.Duration
		if delay != "" {
			duration, err := time.ParseDuration(delay)
			if err != nil {
				return config, fmt.Errorf("invalid delay: %s", delay)
			}
			targetDelay = internal.Duration(duration)
		} else {
			targetDelay = internal.Duration(time.Second)
		}

		target := internal.Target{
			Protocol:       protocol,
			Host:           host,
			Ports:          []int{port},
			Delay:          targetDelay,
			WaitConnection: waitConnection,
		}

		config.Targets = append(config.Targets, target)
	}

	if len(config.Targets) == 0 {
		return config, fmt.Errorf("no valid targets found")
	}

	return config, nil
}
