package main

import (
	"log"
	"os"
	"strconv"

	"git.pyer.club/kingecg/command"
	"git.pyer.club/kingecg/gotunnelserver/client"
	"git.pyer.club/kingecg/gotunnelserver/server"
	"git.pyer.club/kingecg/gotunnelserver/util"
)

type TunnelClient struct {
	TargetSession string `flag_default:"" flag_usage:"target session id"`
	Username      string `flag_default:"tcclient" flag_usage:"username for tunnel server"`
	Salt          string `flag_default:"" flag_usage:"salt for tunnel server"`
	Address       string `flag_default:"ws://127.0.0.1:8080" flag_usage:"address for tunnel server"`
	Host          string `flag_default:"127.0.0.1" flag_usage:"host to proxy to"`
	Port          int    `flag_default:"22" flag_usage:"port to proxy to"`
	LocalPort     int    `flag_default:"0" flag_usage:"local port to accept connection from"`
	LocalHost     string `flag_default:"127.0.0.1" flag_usage:"local host to accept connection from"`
}

var (
	cmdClient *client.CommandClient
	dataEp    *client.DataEndPoint
)

func main() {
	cargs := new(TunnelClient)
	v, _ := command.NewFVSet(cargs)
	err := command.Parse(os.Args[1:], v)
	if err != nil {
		os.Exit(0)
		return
	}

	if cargs.TargetSession == "" {
		log.Fatal("Must set target session to connect to")
		return
	}

	clientConfig := &client.ClientConfig{
		Username: cargs.Username,
		Salt:     cargs.Salt,
		Address:  cargs.Address,
	}
	cmdClient = client.NewClient(clientConfig)
	cmdClient.Once(util.CmdTypeMap[util.ConnectInited], func(args ...interface{}) {
		playload, _ := args[0].(map[string]string)
		sessionId := playload["sessionId"]
		dataEp = client.NewDataEndPoint(cmdClient, sessionId)
		dataEp.Host = cargs.LocalHost
		dataEp.Port = cargs.LocalPort
		go dataEp.Connect()
	})
	cmdClient.On(util.CmdTypeMap[util.NewSession], func(args ...interface{}) {
		cmdClient.Send(&server.Command{
			Type: util.NewConnection,
			Payload: map[string]string{
				"target": cargs.TargetSession,
				"host":   cargs.Host,
				"port":   strconv.Itoa(cargs.Port),
			},
		})
	})

	cmdClient.Once(util.CmdTypeMap[util.ConnectionReady], func(args ...interface{}) {
		go dataEp.Listen()
		log.Println("connection ready")
	})

	cmdClient.On(util.CmdTypeMap[util.ErrorCmd], func(args ...interface{}) {
		playload, _ := args[0].(map[string]string)
		log.Println("error:", playload["error"])
		os.Exit(1)
	})

	defer func() {
		if r := recover(); r != nil {
			log.Println(r)
			return
		}
	}()
	cmdClient.Start()
}
