package main

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"io"
	"log/slog"
	"net/http"
	"os"
	"os/exec"
	"time"

	"github.com/dtoro/oikos/internal/safego"
)

func main() {
	port := os.Getenv("WEBHOOK_LISTEN")
	if port == "" {
		port = ":9797"
	}

	secret := os.Getenv("WEBHOOK_HMAC_SECRET")
	if secret == "" {
		fmt.Fprintln(os.Stderr, "WEBHOOK_HMAC_SECRET must be set")
		os.Exit(1)
	}

	repoDir := os.Getenv("WEBHOOK_REPO_DIR")
	if repoDir == "" {
		repoDir = os.Getenv("HOME") + "/Projects/oikos"
	}

	mux := http.NewServeMux()
	mux.HandleFunc("/deploy", func(w http.ResponseWriter, r *http.Request) {
		if r.Method != http.MethodPost {
			http.Error(w, "method not allowed", 405)
			return
		}

		body, err := io.ReadAll(r.Body)
		if err != nil {
			http.Error(w, "read body failed", 400)
			return
		}

		sigHex := r.Header.Get("X-Hub-Signature-256")
		if sigHex == "" {
			http.Error(w, "missing signature", 401)
			return
		}

		mac := hmac.New(sha256.New, []byte(secret))
		mac.Write(body)
		expected := "sha256=" + hex.EncodeToString(mac.Sum(nil))

		if !hmac.Equal([]byte(sigHex), []byte(expected)) {
			slog.Warn("webhook: invalid signature")
			http.Error(w, "invalid signature", 401)
			return
		}

		slog.Info("webhook: deploy triggered")
		w.WriteHeader(http.StatusAccepted)
		w.Write([]byte(`{"status":"deploy started"}`))

		safego.Go("webhook:deploy", func() {
			cmd := exec.Command(repoDir + "/scripts/deploy.sh")
			cmd.Dir = repoDir
			cmd.Env = append(os.Environ(),
				"REPO_DIR="+repoDir,
				"PROFILE=full",
			)
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr
			start := time.Now()
			if err := cmd.Run(); err != nil {
				slog.Error("webhook: deploy failed", "error", err, "duration", time.Since(start))
				return
			}
			slog.Info("webhook: deploy succeeded", "duration", time.Since(start))
		})
	})

	mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(200)
		w.Write([]byte("ok"))
	})

	slog.Info("webhook: listening", "port", port)
	if err := http.ListenAndServe(port, mux); err != nil {
		slog.Error("webhook: serve failed", "error", err)
		os.Exit(1)
	}
}
