package server

import (
	"encoding/base64"
	"net/mail"
	"strings"

	"galaxy/backend/internal/auth"
)

// ed25519PublicKeyLen is the fixed size of a raw Ed25519 public key. The
// OpenAPI contract documents `client_public_key` as a "Standard
// base64-encoded raw 32-byte Ed25519 public key"; the handler enforces
// the length after decode so the auth service always operates on the
// canonical shape.
const ed25519PublicKeyLen = 32

// deviceSessionPayload is the JSON body the internal session endpoints
// emit. It mirrors the `DeviceSession` schema in `openapi.yaml`.
type deviceSessionPayload struct {
	DeviceSessionID string  `json:"device_session_id"`
	UserID          string  `json:"user_id"`
	Status          string  `json:"status"`
	ClientPublicKey string  `json:"client_public_key,omitempty"`
	CreatedAt       string  `json:"created_at"`
	RevokedAt       *string `json:"revoked_at,omitempty"`
	LastSeenAt      *string `json:"last_seen_at,omitempty"`
}

func deviceSessionToWire(s auth.Session) deviceSessionPayload {
	out := deviceSessionPayload{
		DeviceSessionID: s.DeviceSessionID.String(),
		UserID:          s.UserID.String(),
		Status:          s.Status,
		CreatedAt:       s.CreatedAt.UTC().Format("2006-01-02T15:04:05.000Z07:00"),
	}
	if len(s.ClientPublicKey) > 0 {
		out.ClientPublicKey = base64.StdEncoding.EncodeToString(s.ClientPublicKey)
	}
	if s.RevokedAt != nil {
		formatted := s.RevokedAt.UTC().Format("2006-01-02T15:04:05.000Z07:00")
		out.RevokedAt = &formatted
	}
	if s.LastSeenAt != nil {
		formatted := s.LastSeenAt.UTC().Format("2006-01-02T15:04:05.000Z07:00")
		out.LastSeenAt = &formatted
	}
	return out
}

// validateEmail returns the trimmed value when raw parses as an
// addr-spec, or "" when raw is malformed. Auth normalises to lowercase
// internally; the handler only enforces the syntactic shape.
func validateEmail(raw string) string {
	addr, err := mail.ParseAddress(strings.TrimSpace(raw))
	if err != nil {
		return ""
	}
	return addr.Address
}

// decodeClientPublicKey decodes the wire-format client_public_key into
// raw bytes and validates the length. Standard base64 (with padding) is
// the canonical encoding documented in `openapi.yaml`.
func decodeClientPublicKey(raw string) ([]byte, bool) {
	decoded, err := base64.StdEncoding.DecodeString(strings.TrimSpace(raw))
	if err != nil {
		return nil, false
	}
	if len(decoded) != ed25519PublicKeyLen {
		return nil, false
	}
	return decoded, true
}

// isDecimalCodeOfLength reports whether s is a string of exactly want
// ASCII digits.
func isDecimalCodeOfLength(s string, want int) bool {
	if len(s) != want {
		return false
	}
	for i := 0; i < len(s); i++ {
		if s[i] < '0' || s[i] > '9' {
			return false
		}
	}
	return true
}
