package store

import (
	"context"
	"database/sql"
	"errors"
	"fmt"
	"time"
)

// CredentialKind identifies the role of a host_credentials row.
type CredentialKind string

const (
	// CredKindRepo is the append-only credential used for every backup.
	CredKindRepo CredentialKind = "repo"
	// CredKindAdmin is the delete-capable credential used for prune.
	CredKindAdmin CredentialKind = "admin"
)

// GetHostCredentials returns the AEAD-encrypted repo creds blob for
// the host + kind, or ("", ErrNotFound) if no matching row exists.
// The caller decrypts using host_id as AEAD additional data.
func (s *Store) GetHostCredentials(ctx context.Context, hostID string, kind CredentialKind) (string, error) {
	row := s.db.QueryRowContext(ctx,
		`SELECT enc_repo_creds FROM host_credentials WHERE host_id = ? AND kind = ?`,
		hostID, string(kind))
	var enc string
	if err := row.Scan(&enc); err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return "", ErrNotFound
		}
		return "", fmt.Errorf("store: get host credentials: %w", err)
	}
	return enc, nil
}

// SetHostCredentials replaces the host's encrypted repo creds blob for
// the given kind. The caller has already encrypted using host_id as
// additional data.
func (s *Store) SetHostCredentials(ctx context.Context, hostID string, kind CredentialKind, encRepoCreds string) error {
	if encRepoCreds == "" {
		return fmt.Errorf("store: empty enc_repo_creds")
	}
	now := time.Now().UTC().Format(time.RFC3339Nano)
	_, err := s.db.ExecContext(ctx,
		`INSERT INTO host_credentials (host_id, kind, enc_repo_creds, updated_at)
		 VALUES (?, ?, ?, ?)
		 ON CONFLICT(host_id, kind) DO UPDATE SET
			enc_repo_creds = excluded.enc_repo_creds,
			updated_at     = excluded.updated_at`,
		hostID, string(kind), encRepoCreds, now)
	if err != nil {
		return fmt.Errorf("store: set host credentials: %w", err)
	}
	return nil
}

// DeleteHostCredentials removes the credential row for the given host
// and kind. A no-op if the row does not exist.
func (s *Store) DeleteHostCredentials(ctx context.Context, hostID string, kind CredentialKind) error {
	_, err := s.db.ExecContext(ctx,
		`DELETE FROM host_credentials WHERE host_id = ? AND kind = ?`,
		hostID, string(kind))
	if err != nil {
		return fmt.Errorf("store: delete host credentials: %w", err)
	}
	return nil
}
