package system

import (
	"context"
	"regexp"
	"strings"

	"nadir/internal/oscmd"

	"github.com/danielgtaylor/huma/v2"
)

// hostnameRe matches RFC-1123 labels joined by dots, max 253 chars total. Anchored
// so a leading "-" can't be read as a hostnamectl flag and shell metacharacters
// can't survive — same pattern the other modules use (CLAUDE.md §5).
var hostnameRe = regexp.MustCompile(`^[a-zA-Z0-9]([a-zA-Z0-9-]{0,62})(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,62}))*$`)

type HostnameBody struct {
	Hostname string `json:"hostname" example:"server01" doc:"System hostname"`
}

type GetHostnameOutput struct{ Body HostnameBody }
type SetHostnameInput struct{ Body HostnameBody }

func registerHostname(api huma.API) {
	huma.Register(api, huma.Operation{
		OperationID: "system-get-hostname",
		Method:      "GET",
		Path:        "/api/system/hostname",
		Summary:     "Get system hostname",
		Description: "Returns the current hostname as reported by hostnamectl.",
		Tags:        []string{tagSystem},
		Metadata:    op("read"),
		Errors:      readErrors,
	}, func(ctx context.Context, _ *struct{}) (*GetHostnameOutput, error) {
		name, err := oscmd.Run("hostnamectl", "hostname")
		if err != nil {
			return nil, huma.Error500InternalServerError("hostnamectl failed", err)
		}
		return &GetHostnameOutput{Body: HostnameBody{Hostname: name}}, nil
	})

	huma.Register(api, huma.Operation{
		OperationID: "system-set-hostname",
		Method:      "POST",
		Path:        "/api/system/hostname",
		Summary:     "Set system hostname",
		Description: "Sets the static hostname via hostnamectl, which owns " +
			"/etc/hostname and manages the static/pretty/transient names.",
		Tags:     []string{tagSystem},
		Metadata: op("write"),
		Errors:   writeErrors,
	}, func(ctx context.Context, in *SetHostnameInput) (*oscmd.StatusOutput, error) {
		name := strings.TrimSpace(in.Body.Hostname)
		if name == "" {
			return nil, huma.Error400BadRequest("empty hostname")
		}
		if len(name) > 253 || !hostnameRe.MatchString(name) {
			return nil, huma.Error400BadRequest("invalid hostname: " + name)
		}
		if _, err := oscmd.Run("hostnamectl", "set-hostname", "--", name); err != nil {
			return nil, huma.Error500InternalServerError("hostnamectl failed", err)
		}
		return oscmd.OK(), nil
	})
}
