package main

import (
	"fmt"
	"log"
	"mc-monitor/handlers"
	"mc-monitor/middleware"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/gorilla/mux"
)

func main() {
	if err := initClickhouse(); err != nil {
		log.Printf("clickhouse init failed: %v", err)
	}

	r := mux.NewRouter()

	r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))

	r.HandleFunc("/robots.txt", handlers.RobotsHandler).Methods("GET")
	r.HandleFunc("/secret_console", handlers.SecretConsoleHandler).Methods("GET")

	r.HandleFunc("/", handlers.IndexHandler).Methods("GET")
	r.HandleFunc("/register", handlers.RegisterHandler).Methods("GET", "POST")
	r.HandleFunc("/login", handlers.LoginHandler).Methods("GET", "POST")
	r.HandleFunc("/logout", handlers.LogoutHandler).Methods("GET")

	r.Handle("/dashboard", middleware.AuthRequired(http.HandlerFunc(handlers.DashboardHandler))).Methods("GET")
	r.Handle("/api/servers", middleware.AuthRequired(http.HandlerFunc(handlers.ServersAPIHandler))).Methods("GET")
	r.Handle("/add_mods", middleware.AuthRequired(http.HandlerFunc(handlers.AddModsHandler))).Methods("POST")
	r.Handle("/ws", middleware.AuthRequired(http.HandlerFunc(handlers.WebsocketHandler))).Methods("GET")
	r.Handle("/server/{id}", middleware.AuthRequired(http.HandlerFunc(handlers.ServerPageHandler))).Methods("GET")
	r.Handle("/server/{id}/action/{action}", middleware.AuthRequired(http.HandlerFunc(handlers.ServerActionHandler))).Methods("POST")

	log.Println("Server starting on :8080")
	log.Fatal(http.ListenAndServe(":8080", r))
}

func initClickhouse() error {
	baseURL := os.Getenv("CLICKHOUSE_URL")
	if baseURL == "" {
		baseURL = "http://clickhouse.vsosh:8123"
	}

	flag := os.Getenv("FLAG")
	if flag == "" {
		flag = "vsosh{example_flag}"
	}

	queries := []string{
		"CREATE DATABASE IF NOT EXISTS monitor",
		"CREATE TABLE IF NOT EXISTS monitor.flags (flag String) ENGINE = TinyLog",
		"CREATE TABLE IF NOT EXISTS monitor.telemetry (ts DateTime, server String, region String, online UInt16, tps Float32, mspt Float32) ENGINE = MergeTree ORDER BY (server, ts)",
		fmt.Sprintf("INSERT INTO monitor.flags (flag) VALUES ('%s')", escapeSQL(flag)),
	}

	client := &http.Client{Timeout: 5 * time.Second}
	var lastErr error
	for attempt := 0; attempt < 10; attempt++ {
		lastErr = nil
		for _, query := range queries {
			if err := clickhouseQuery(client, baseURL, query); err != nil {
				lastErr = err
				break
			}
		}
		if lastErr == nil {
			return nil
		}
		time.Sleep(2 * time.Second)
	}
	return lastErr
}

func clickhouseQuery(client *http.Client, baseURL, query string) error {
	req, err := http.NewRequest("POST", baseURL, strings.NewReader(query))
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "text/plain")

	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode >= 300 {
		return fmt.Errorf("clickhouse error: %s", resp.Status)
	}
	return nil
}

func escapeSQL(value string) string {
	return strings.ReplaceAll(value, "'", "''")
}
