package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"strings"
	"time"

	"golang.org/x/net/html"
)

// Config represents the configuration structure
type Config struct {
	Username string `json:"username"`
	Password string `json:"password"`
	Domain   string `json:"domain"`
}

func main() {
	// Load or create the configuration file
	config, err := readOrCreateConfig("config.json")
	if err != nil {
		fmt.Println("配置文件处理出错:", err)
		return
	}

	// Schedule a task to run every 5 seconds
	ticker := time.NewTicker(5 * time.Second)
	defer ticker.Stop()

	for {
		select {
		case <-ticker.C:
			// Check if baidu.com is reachable
			if !ping("180.101.50.242") {
				fmt.Println("keep alive no res")
				if err := performLogin(config); err != nil {
					fmt.Println("执行登录操作出错:", err)
				}
			}
		}
	}
}

// performLogin performs the login operation
func performLogin(config Config) error {
	// Fetch the HTML content
	resp, err := http.Get("http://211.70.248.14/srun_portal_pc.php?ac_id=9&")
	if err != nil {
		return fmt.Errorf("GET请求出错: %w", err)
	}
	defer resp.Body.Close()

	// Read the response body
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return fmt.Errorf("读取响应出错: %w", err)
	}

	htmlContent := string(body)

	// Parse HTML to extract form information
	action, acID, userIP := parseForm(htmlContent)

	action = "http://211.70.248.14/srun_portal_pc.php?ac_id=9&"

	fmt.Printf("Form Info:\nAction: %s\nAC_ID: %s\nUser_IP: %s\n", action, acID, userIP)

	// Construct POST data
	formData := url.Values{
		"action":   {"login"},
		"ac_id":    {acID},
		"user_ip":  {userIP},
		"username": {config.Username},
		"password": {config.Password},
	}

	// Set domain based on the configuration
	switch config.Domain {
	case "CT":
		formData.Add("domain", "@telcom")
	case "CM":
		formData.Add("domain", "@cmcc")
	default:
		formData.Add("domain", "")
	}

	// Send POST request
	resp, err = http.PostForm(action, formData)
	if err != nil {
		return fmt.Errorf("POST请求出错: %w", err)
	}
	defer resp.Body.Close()

	return nil
}

// readOrCreateConfig reads or creates the configuration file
func readOrCreateConfig(filePath string) (Config, error) {
	var config Config

	// Try reading the configuration file
	configFile, err := ioutil.ReadFile(filePath)
	if err == nil {
		// File exists, parse the configuration file
		err = json.Unmarshal(configFile, &config)
		if err != nil {
			return config, fmt.Errorf("解析配置文件出错: %w", err)
		}
		return config, nil
	}

	// File does not exist, create a default configuration file
	if os.IsNotExist(err) {
		defaultConfig := Config{
			Username: "your_username",
			Password: "your_password",
			Domain:   "CT",
		}
		configJSON, _ := json.MarshalIndent(defaultConfig, "", "  ")
		err = ioutil.WriteFile(filePath, configJSON, 0644)
		if err != nil {
			return config, fmt.Errorf("创建配置文件出错: %w", err)
		}
		fmt.Println("配置文件已创建，使用默认值。请编辑配置文件以更新信息。")
		return defaultConfig, nil
	}

	return config, fmt.Errorf("读取配置文件出错: %w", err)
}

// parseForm parses the HTML content to extract form information
func parseForm(htmlContent string) (action, acID, userIP string) {
	doc, err := html.Parse(strings.NewReader(htmlContent))
	if err != nil {
		fmt.Println("解析HTML出错:", err)
		return
	}

	var parse func(*html.Node)
	parse = func(n *html.Node) {
		if n.Type == html.ElementNode && n.Data == "form" {
			for _, a := range n.Attr {
				if a.Key == "action" {
					action = a.Val
				}
			}
		}
		if n.Type == html.ElementNode && n.Data == "input" {
			for _, a := range n.Attr {
				if a.Key == "name" {
					switch a.Val {
					case "ac_id":
						acID = getInputValue(n)
					case "user_ip":
						userIP = getInputValue(n)
					}
				}
			}
		}
		for c := n.FirstChild; c != nil; c = c.NextSibling {
			parse(c)
		}
	}

	parse(doc)
	return
}

// getInputValue gets the value of an input element
func getInputValue(n *html.Node) string {
	for _, a := range n.Attr {
		if a.Key == "value" {
			return a.Val
		}
	}
	return ""
}

// ping checks if the given host is reachable
func ping(host string) bool {
	cmd := exec.Command("ping", "-c", "1", host)
	err := cmd.Run()
	if err != nil {
		fmt.Println("Ping 错误:", err)
		return false
	}
	return true
}
