package main

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/YspCoder/clawgo/pkg/bus"
	"github.com/YspCoder/clawgo/pkg/channels"
	"github.com/YspCoder/clawgo/pkg/config"

	qrterminal "github.com/mdp/qrterminal/v3"
)

func channelCmd() {
	if len(os.Args) < 3 {
		channelHelp()
		return
	}

	subcommand := os.Args[2]

	switch subcommand {
	case "test":
		channelTestCmd()
	case "whatsapp":
		whatsAppChannelCmd()
	default:
		fmt.Printf("Unknown channel command: %s\n", subcommand)
		channelHelp()
	}
}

func channelHelp() {
	fmt.Println("\nChannel commands:")
	fmt.Println("  test              Send a test message to a specific channel")
	fmt.Println("  whatsapp          Run and inspect the built-in WhatsApp bridge")
	fmt.Println()
	fmt.Println("Test options:")
	fmt.Println("  --to             Recipient ID")
	fmt.Println("  --channel        Channel name (telegram, discord, etc.)")
	fmt.Println("  -m, --message    Message to send")
	fmt.Println()
	fmt.Println("WhatsApp bridge:")
	fmt.Println("  clawgo channel whatsapp bridge run")
	fmt.Println("  clawgo channel whatsapp bridge status")
	fmt.Println("  clawgo channel whatsapp bridge logout")
}

func channelTestCmd() {
	to := ""
	channelName := ""
	message := "This is a test message from ClawGo"

	args := os.Args[3:]
	for i := 0; i < len(args); i++ {
		switch args[i] {
		case "--to":
			if i+1 < len(args) {
				to = args[i+1]
				i++
			}
		case "--channel":
			if i+1 < len(args) {
				channelName = args[i+1]
				i++
			}
		case "-m", "--message":
			if i+1 < len(args) {
				message = args[i+1]
				i++
			}
		}
	}

	if channelName == "" || to == "" {
		fmt.Println("Error: --channel and --to are required")
		return
	}

	cfg, err := loadConfig()
	if err != nil {
		fmt.Printf("Error loading config: %v\n", err)
		os.Exit(1)
	}

	msgBus := bus.NewMessageBus()
	mgr, err := channels.NewManager(cfg, msgBus)
	if err != nil {
		fmt.Printf("Error creating channel manager: %v\n", err)
		os.Exit(1)
	}

	ctx := context.Background()
	if err := mgr.StartAll(ctx); err != nil {
		fmt.Printf("Error starting channels: %v\n", err)
		os.Exit(1)
	}

	fmt.Printf("Sending test message to %s (%s)...\n", channelName, to)
	if err := mgr.SendToChannel(ctx, channelName, to, message); err != nil {
		fmt.Printf("Failed to send message: %v\n", err)
		os.Exit(1)
	}

	fmt.Println("Test message sent successfully.")
}

func whatsAppChannelCmd() {
	if len(os.Args) < 4 {
		whatsAppChannelHelp()
		return
	}
	if os.Args[3] != "bridge" {
		fmt.Printf("Unknown WhatsApp channel command: %s\n", os.Args[3])
		whatsAppChannelHelp()
		return
	}
	if len(os.Args) < 5 {
		whatsAppBridgeHelp()
		return
	}
	switch os.Args[4] {
	case "run":
		whatsAppBridgeRunCmd()
	case "status":
		whatsAppBridgeStatusCmd()
	case "logout":
		whatsAppBridgeLogoutCmd()
	default:
		fmt.Printf("Unknown WhatsApp bridge command: %s\n", os.Args[4])
		whatsAppBridgeHelp()
	}
}

func whatsAppChannelHelp() {
	fmt.Println("\nWhatsApp channel commands:")
	fmt.Println("  clawgo channel whatsapp bridge run")
	fmt.Println("  clawgo channel whatsapp bridge status")
	fmt.Println("  clawgo channel whatsapp bridge logout")
}

func whatsAppBridgeHelp() {
	fmt.Println("\nWhatsApp bridge commands:")
	fmt.Println("  run               Run the built-in local WhatsApp bridge with QR login")
	fmt.Println("  status            Show current WhatsApp bridge status")
	fmt.Println("  logout            Unlink the current WhatsApp companion session")
	fmt.Println()
	fmt.Println("Run options:")
	fmt.Println("  --addr <host:port>        Override listen address (defaults to channels.whatsapp.bridge_url host)")
	fmt.Println("  --state-dir <path>        Override session store directory")
	fmt.Println("  --no-print-qr            Disable terminal QR rendering")
}

func whatsAppBridgeRunCmd() {
	cfg, _ := loadConfig()
	bridgeURL := "ws://127.0.0.1:3001"
	if cfg != nil && strings.TrimSpace(cfg.Channels.WhatsApp.BridgeURL) != "" {
		bridgeURL = cfg.Channels.WhatsApp.BridgeURL
	}
	addr, err := channels.ParseWhatsAppBridgeListenAddr(bridgeURL)
	if err != nil {
		fmt.Printf("Error parsing WhatsApp bridge url: %v\n", err)
		os.Exit(1)
	}
	stateDir := filepath.Join(config.GetConfigDir(), "channels", "whatsapp")
	printQR := true
	args := os.Args[5:]
	for i := 0; i < len(args); i++ {
		switch args[i] {
		case "--addr":
			if i+1 < len(args) {
				addr = strings.TrimSpace(args[i+1])
				i++
			}
		case "--state-dir":
			if i+1 < len(args) {
				stateDir = strings.TrimSpace(args[i+1])
				i++
			}
		case "--no-print-qr":
			printQR = false
		}
	}

	fmt.Printf("Starting WhatsApp bridge on %s\n", addr)
	fmt.Printf("Session store: %s\n", stateDir)
	statusURL, _ := channels.BridgeStatusURL(addr)
	fmt.Printf("Status endpoint: %s\n", statusURL)
	if printQR {
		fmt.Println("QR codes will be rendered below when login is required.")
	}

	svc := channels.NewWhatsAppBridgeService(addr, stateDir, printQR)
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	go renderWhatsAppBridgeQR(ctx, addr, printQR)
	go renderWhatsAppBridgeState(ctx, addr)
	if err := svc.Start(ctx); err != nil {
		fmt.Printf("WhatsApp bridge stopped with error: %v\n", err)
		os.Exit(1)
	}
}

func whatsAppBridgeStatusCmd() {
	cfg, _ := loadConfig()
	bridgeURL := "ws://127.0.0.1:3001"
	if cfg != nil && strings.TrimSpace(cfg.Channels.WhatsApp.BridgeURL) != "" {
		bridgeURL = cfg.Channels.WhatsApp.BridgeURL
	}
	args := os.Args[5:]
	if len(args) >= 2 && args[0] == "--url" {
		bridgeURL = strings.TrimSpace(args[1])
	}
	statusURL, err := channels.BridgeStatusURL(bridgeURL)
	if err != nil {
		fmt.Printf("Error building status url: %v\n", err)
		os.Exit(1)
	}
	status, err := fetchWhatsAppBridgeStatus(statusURL)
	if err != nil {
		fmt.Printf("Error fetching WhatsApp bridge status: %v\n", err)
		os.Exit(1)
	}
	data, _ := json.MarshalIndent(status, "", "  ")
	fmt.Println(string(data))
	if status.QRAvailable && strings.TrimSpace(status.QRCode) != "" {
		fmt.Println()
		fmt.Println("Scan this QR code with WhatsApp:")
		qrterminal.GenerateHalfBlock(status.QRCode, qrterminal.L, os.Stdout)
	}
}

func whatsAppBridgeLogoutCmd() {
	cfg, _ := loadConfig()
	bridgeURL := "ws://127.0.0.1:3001"
	if cfg != nil && strings.TrimSpace(cfg.Channels.WhatsApp.BridgeURL) != "" {
		bridgeURL = cfg.Channels.WhatsApp.BridgeURL
	}
	args := os.Args[5:]
	if len(args) >= 2 && args[0] == "--url" {
		bridgeURL = strings.TrimSpace(args[1])
	}
	logoutURL, err := channels.BridgeLogoutURL(bridgeURL)
	if err != nil {
		fmt.Printf("Error building logout url: %v\n", err)
		os.Exit(1)
	}
	req, _ := http.NewRequest(http.MethodPost, logoutURL, nil)
	resp, err := (&http.Client{Timeout: 20 * time.Second}).Do(req)
	if err != nil {
		fmt.Printf("Error calling WhatsApp bridge logout: %v\n", err)
		os.Exit(1)
	}
	defer resp.Body.Close()
	if resp.StatusCode >= 300 {
		fmt.Printf("WhatsApp bridge logout failed: %s\n", resp.Status)
		os.Exit(1)
	}
	fmt.Println("WhatsApp bridge logout requested successfully.")
}

func fetchWhatsAppBridgeStatus(statusURL string) (channels.WhatsAppBridgeStatus, error) {
	resp, err := (&http.Client{Timeout: 8 * time.Second}).Get(statusURL)
	if err != nil {
		return channels.WhatsAppBridgeStatus{}, err
	}
	defer resp.Body.Close()
	if resp.StatusCode >= 300 {
		return channels.WhatsAppBridgeStatus{}, fmt.Errorf("status request failed: %s", resp.Status)
	}
	var status channels.WhatsAppBridgeStatus
	if err := json.NewDecoder(resp.Body).Decode(&status); err != nil {
		return channels.WhatsAppBridgeStatus{}, err
	}
	return status, nil
}

func renderWhatsAppBridgeQR(ctx context.Context, bridgeURL string, enabled bool) {
	if !enabled {
		return
	}
	statusURL, err := channels.BridgeStatusURL(bridgeURL)
	if err != nil {
		return
	}
	ticker := time.NewTicker(3 * time.Second)
	defer ticker.Stop()
	lastQR := ""
	for {
		select {
		case <-ctx.Done():
			return
		case <-ticker.C:
			status, err := fetchWhatsAppBridgeStatus(statusURL)
			if err != nil {
				continue
			}
			if !status.QRAvailable || strings.TrimSpace(status.QRCode) == "" || status.QRCode == lastQR {
				continue
			}
			lastQR = status.QRCode
			fmt.Println()
			fmt.Println("Scan this QR code with WhatsApp:")
			qrterminal.GenerateHalfBlock(status.QRCode, qrterminal.L, os.Stdout)
			fmt.Println()
		}
	}
}

func renderWhatsAppBridgeState(ctx context.Context, bridgeURL string) {
	statusURL, err := channels.BridgeStatusURL(bridgeURL)
	if err != nil {
		return
	}
	ticker := time.NewTicker(2 * time.Second)
	defer ticker.Stop()

	var lastSig string
	var lastPrintedUser string
	for {
		select {
		case <-ctx.Done():
			return
		case <-ticker.C:
			status, err := fetchWhatsAppBridgeStatus(statusURL)
			if err != nil {
				continue
			}
			sig := fmt.Sprintf("%s|%t|%t|%s|%s", status.State, status.Connected, status.LoggedIn, status.UserJID, status.LastEvent)
			if sig == lastSig {
				continue
			}
			lastSig = sig

			switch {
			case status.QRAvailable:
				fmt.Println("Waiting for WhatsApp QR scan...")
			case status.State == "paired":
				fmt.Println("WhatsApp QR scanned. Finalizing companion link...")
			case status.Connected && status.LoggedIn:
				if status.UserJID != "" && status.UserJID != lastPrintedUser {
					fmt.Printf("WhatsApp connected as %s\n", status.UserJID)
					lastPrintedUser = status.UserJID
				} else {
					fmt.Println("WhatsApp bridge connected.")
				}
				fmt.Println("Bridge is ready. Start or keep `make dev` running to receive messages.")
			case status.State == "stored_session":
				fmt.Println("Existing WhatsApp session found. Reconnecting...")
			case status.State == "disconnected":
				fmt.Println("WhatsApp bridge disconnected. Waiting for reconnect...")
			case status.State == "logged_out":
				fmt.Println("WhatsApp session logged out. Restart bridge to scan a new QR code.")
			case status.LastError != "":
				fmt.Printf("WhatsApp bridge status: %s (%s)\n", status.State, status.LastError)
			case status.State != "":
				fmt.Printf("WhatsApp bridge status: %s\n", status.State)
			}
		}
	}
}
