package pbs

import (
	"crypto/sha256"
	"crypto/tls"
	"crypto/x509"
	"encoding/hex"
	"fmt"
	"strings"
)

// pinnedTLS builds a tls.Config that pins the PBS server's leaf cert by SHA-256 — the same
// model as the PVE client (proxmox/tls.go). PBS serves a self-signed cert, so we disable the
// default chain check but enforce an exact-cert match: a spoofed PBS presents a different
// fingerprint and is rejected. fingerprint is hex with optional colons (the form in
// /etc/pve/storage.cfg and the slice-5 durable_id).
func pinnedTLS(fingerprint string) (*tls.Config, error) {
	want, err := normalizeFingerprint(fingerprint)
	if err != nil {
		return nil, err
	}
	return &tls.Config{
		InsecureSkipVerify: true, //nolint:gosec // replaced by the exact-cert pin below
		VerifyPeerCertificate: func(rawCerts [][]byte, _ [][]*x509.Certificate) error {
			if len(rawCerts) == 0 {
				return fmt.Errorf("pbs: TLS pin: peer presented no certificate")
			}
			got := sha256.Sum256(rawCerts[0])
			if hex.EncodeToString(got[:]) != want {
				return fmt.Errorf("pbs: TLS pin mismatch: server cert sha256 does not match configured fingerprint")
			}
			return nil
		},
	}, nil
}

// normalizeFingerprint lowercases and strips colons/whitespace, validating a 64-char
// (32-byte) hex SHA-256.
func normalizeFingerprint(fp string) (string, error) {
	s := strings.ToLower(strings.NewReplacer(":", "", " ", "", "\t", "").Replace(fp))
	if len(s) != 64 {
		return "", fmt.Errorf("pbs: fingerprint must be a SHA-256 (64 hex chars), got %d", len(s))
	}
	if _, err := hex.DecodeString(s); err != nil {
		return "", fmt.Errorf("pbs: fingerprint is not valid hex: %w", err)
	}
	return s, nil
}
