package lib

import (
	"database/sql"
	"errors"
	"fmt"

	_ "github.com/mattn/go-sqlite3"
)

const tokenMapSchema = `
CREATE TABLE IF NOT EXISTS token_map (
    token    TEXT PRIMARY KEY,
    vault_id INTEGER NOT NULL
);
`

// TokenMap wraps node.db for token→vault_id lookups.
type TokenMap struct {
	db *sql.DB
}

// OpenTokenMap opens (or creates) the node.db token registry.
func OpenTokenMap(dbPath string) (*TokenMap, error) {
	conn, err := sql.Open("sqlite3", dbPath+"?_journal_mode=WAL&_busy_timeout=5000")
	if err != nil {
		return nil, fmt.Errorf("open token map: %w", err)
	}
	if _, err := conn.Exec(tokenMapSchema); err != nil {
		conn.Close()
		return nil, fmt.Errorf("migrate token map: %w", err)
	}
	return &TokenMap{db: conn}, nil
}

// Close closes the token map database.
func (tm *TokenMap) Close() error {
	return tm.db.Close()
}

// Register adds a token→vault_id mapping.
func (tm *TokenMap) Register(token string, vaultID int64) error {
	_, err := tm.db.Exec(
		`INSERT OR REPLACE INTO token_map (token, vault_id) VALUES (?, ?)`,
		token, vaultID,
	)
	return err
}

// Lookup resolves a token to a vault_id. Returns 0, nil if not found.
func (tm *TokenMap) Lookup(token string) (int64, error) {
	var vaultID int64
	err := tm.db.QueryRow(`SELECT vault_id FROM token_map WHERE token = ?`, token).Scan(&vaultID)
	if errors.Is(err, sql.ErrNoRows) {
		return 0, nil
	}
	return vaultID, err
}

// Remove deletes a token mapping.
func (tm *TokenMap) Remove(token string) error {
	_, err := tm.db.Exec(`DELETE FROM token_map WHERE token = ?`, token)
	return err
}

// RemoveAllForVault removes all tokens for a vault.
func (tm *TokenMap) RemoveAllForVault(vaultID int64) error {
	_, err := tm.db.Exec(`DELETE FROM token_map WHERE vault_id = ?`, vaultID)
	return err
}
