import assert from "node:assert/strict"
import Database from "better-sqlite3"
import { normalizeBindingPeer, PeerBindError } from "./peer-bind.js"

const sqlite = new Database(":memory:")
sqlite.pragma("foreign_keys = ON")
sqlite.exec(`
CREATE TABLE servers (
  id INTEGER PRIMARY KEY,
  name TEXT NOT NULL DEFAULT '',
  host TEXT NOT NULL DEFAULT '127.0.0.1'
);
CREATE TABLE app_users (
  id TEXT PRIMARY KEY,
  name TEXT NOT NULL DEFAULT '',
  login TEXT NOT NULL UNIQUE,
  email TEXT NOT NULL DEFAULT '',
  role TEXT NOT NULL DEFAULT 'viewer',
  active INTEGER NOT NULL DEFAULT 1,
  avatar TEXT NOT NULL DEFAULT '',
  last_seen TEXT,
  sections_json TEXT NOT NULL DEFAULT '[]',
  servers_json TEXT NOT NULL DEFAULT '[]',
  created_at TEXT NOT NULL DEFAULT (datetime('now')),
  updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE user_interface_bindings (
  id TEXT PRIMARY KEY,
  user_id TEXT NOT NULL,
  server_id INTEGER NOT NULL,
  interface_name TEXT NOT NULL,
  interface_type TEXT NOT NULL DEFAULT 'other',
  peer_public_key TEXT NOT NULL DEFAULT '',
  peer_name TEXT NOT NULL DEFAULT '',
  comment TEXT NOT NULL DEFAULT '',
  created_at TEXT NOT NULL DEFAULT (datetime('now')),
  updated_at TEXT NOT NULL DEFAULT (datetime('now')),
  FOREIGN KEY (user_id) REFERENCES app_users(id) ON DELETE CASCADE,
  FOREIGN KEY (server_id) REFERENCES servers(id) ON DELETE CASCADE,
  UNIQUE (server_id, interface_name, peer_public_key)
);
`)

sqlite.prepare("INSERT INTO servers (id, name, host) VALUES (1, 'jh', '10.0.0.1')").run()
sqlite.prepare("INSERT INTO app_users (id, name, login) VALUES ('u1', 'A', 'a.user')").run()
sqlite.prepare("INSERT INTO app_users (id, name, login) VALUES ('u2', 'B', 'b.user')").run()
sqlite.prepare(`
  INSERT INTO user_interface_bindings (id, user_id, server_id, interface_name, interface_type)
  VALUES ('b1', 'u1', 1, 'gre-office', 'gre')
`).run()

assert.throws(
  () => sqlite.prepare(`
    INSERT INTO user_interface_bindings (id, user_id, server_id, interface_name, interface_type)
    VALUES ('b2', 'u2', 1, 'gre-office', 'gre')
  `).run(),
  /UNIQUE/i,
  "один интерфейс на сервере — один пользователь",
)

sqlite.prepare(`
  INSERT INTO user_interface_bindings (id, user_id, server_id, interface_name, interface_type, peer_public_key, peer_name)
  VALUES ('wg1', 'u1', 1, 'wg-server', 'wg', 'peer-key-aaa', 'phone')
`).run()
sqlite.prepare(`
  INSERT INTO user_interface_bindings (id, user_id, server_id, interface_name, interface_type, peer_public_key, peer_name)
  VALUES ('wg2', 'u2', 1, 'wg-server', 'wg', 'peer-key-bbb', 'laptop')
`).run()
assert.throws(
  () => sqlite.prepare(`
    INSERT INTO user_interface_bindings (id, user_id, server_id, interface_name, interface_type, peer_public_key)
    VALUES ('wg3', 'u2', 1, 'wg-server', 'wg', 'peer-key-aaa')
  `).run(),
  /UNIQUE/i,
  "один пир — один пользователь",
)

assert.throws(
  () => normalizeBindingPeer("wg", ""),
  (err: unknown) => err instanceof PeerBindError && err.status === 400,
  "WG без ключа — 400",
)
assert.equal(normalizeBindingPeer("ether", "ignored"), "")
assert.equal(normalizeBindingPeer("wg", " abc "), "abc")

sqlite.prepare("DELETE FROM app_users WHERE id = 'u1'").run()
const leftover = sqlite.prepare("SELECT COUNT(*) AS n FROM user_interface_bindings").get() as { n: number }
assert.equal(leftover.n, 1, "каскад: привязки u1 удаляются, пир u2 остаётся")

console.log("users bindings unique+cascade tests ok")
