package ssh

import (
	"database/sql"
	"fmt"
)

// HostKeyResult represents the result of a host key verification.
type HostKeyResult int

const (
	HostKeyNew     HostKeyResult = iota // never seen this host before
	HostKeyMatch                        // fingerprint matches stored
	HostKeyChanged                      // fingerprint CHANGED — possible MITM
)

// HostKeyStore stores and verifies SSH host key fingerprints in the host_keys SQLite table.
type HostKeyStore struct {
	db *sql.DB
}

// NewHostKeyStore creates a new HostKeyStore backed by the given database.
func NewHostKeyStore(db *sql.DB) *HostKeyStore {
	return &HostKeyStore{db: db}
}

// Verify checks whether the given fingerprint matches any stored host key for the
// specified hostname, port, and key type. It returns HostKeyNew if no key is stored,
// HostKeyMatch if the fingerprint matches, or HostKeyChanged if it differs.
func (s *HostKeyStore) Verify(hostname string, port int, keyType string, fingerprint string) (HostKeyResult, error) {
	var storedFingerprint string
	err := s.db.QueryRow(
		"SELECT fingerprint FROM host_keys WHERE hostname = ? AND port = ? AND key_type = ?",
		hostname, port, keyType,
	).Scan(&storedFingerprint)

	if err == sql.ErrNoRows {
		return HostKeyNew, nil
	}
	if err != nil {
		return 0, fmt.Errorf("query host key: %w", err)
	}

	if storedFingerprint == fingerprint {
		return HostKeyMatch, nil
	}
	return HostKeyChanged, nil
}

// Store inserts or replaces a host key fingerprint for the given hostname, port, and key type.
func (s *HostKeyStore) Store(hostname string, port int, keyType string, fingerprint string, rawKey string) error {
	_, err := s.db.Exec(
		`INSERT INTO host_keys (hostname, port, key_type, fingerprint, raw_key)
		 VALUES (?, ?, ?, ?, ?)
		 ON CONFLICT (hostname, port, key_type)
		 DO UPDATE SET fingerprint = excluded.fingerprint, raw_key = excluded.raw_key`,
		hostname, port, keyType, fingerprint, rawKey,
	)
	if err != nil {
		return fmt.Errorf("store host key: %w", err)
	}
	return nil
}

// Delete removes all stored host keys for the given hostname and port.
func (s *HostKeyStore) Delete(hostname string, port int) error {
	_, err := s.db.Exec(
		"DELETE FROM host_keys WHERE hostname = ? AND port = ?",
		hostname, port,
	)
	if err != nil {
		return fmt.Errorf("delete host key: %w", err)
	}
	return nil
}

// GetFingerprint returns the stored fingerprint for the given hostname and port.
// It returns an empty string and sql.ErrNoRows if no key is stored.
func (s *HostKeyStore) GetFingerprint(hostname string, port int) (string, error) {
	var fingerprint string
	err := s.db.QueryRow(
		"SELECT fingerprint FROM host_keys WHERE hostname = ? AND port = ?",
		hostname, port,
	).Scan(&fingerprint)
	if err != nil {
		return "", fmt.Errorf("get fingerprint: %w", err)
	}
	return fingerprint, nil
}
