-- +up
CREATE TABLE IF NOT EXISTS wrn_auth_users (
  id VARCHAR(191) PRIMARY KEY,
  username VARCHAR(191),
  display_name VARCHAR(191),
  avatar_url TEXT,
  status VARCHAR(32) NOT NULL,
  roles_json TEXT NOT NULL,
  email_verified INTEGER NOT NULL DEFAULT 0,
  phone_verified INTEGER NOT NULL DEFAULT 0,
  mfa_enabled INTEGER NOT NULL DEFAULT 0,
  locale VARCHAR(32),
  timezone VARCHAR(64),
  created_at BIGINT NOT NULL,
  updated_at BIGINT NOT NULL,
  last_login_at BIGINT,
  metadata_json TEXT
);

CREATE UNIQUE INDEX IF NOT EXISTS wrn_auth_users_username_uq ON wrn_auth_users(username);

CREATE TABLE IF NOT EXISTS wrn_auth_identities (
  id VARCHAR(191) PRIMARY KEY,
  user_id VARCHAR(191) NOT NULL,
  type VARCHAR(32) NOT NULL,
  value VARCHAR(320) NOT NULL,
  normalized_value VARCHAR(320) NOT NULL,
  is_primary INTEGER NOT NULL DEFAULT 0,
  verified_at BIGINT,
  created_at BIGINT NOT NULL,
  updated_at BIGINT NOT NULL,
  UNIQUE(type, normalized_value)
);

CREATE INDEX IF NOT EXISTS wrn_auth_identities_user_idx ON wrn_auth_identities(user_id);

CREATE TABLE IF NOT EXISTS wrn_auth_password_credentials (
  user_id VARCHAR(191) PRIMARY KEY,
  password_hash TEXT NOT NULL,
  password_version INTEGER NOT NULL DEFAULT 1,
  changed_at BIGINT NOT NULL,
  must_change INTEGER NOT NULL DEFAULT 0
);

CREATE TABLE IF NOT EXISTS wrn_auth_sessions (
  id VARCHAR(191) PRIMARY KEY,
  user_id VARCHAR(191) NOT NULL,
  device_id VARCHAR(191) NOT NULL,
  created_at BIGINT NOT NULL,
  last_seen_at BIGINT NOT NULL,
  expires_at BIGINT NOT NULL,
  absolute_expires_at BIGINT NOT NULL,
  ip VARCHAR(64),
  user_agent TEXT,
  trusted INTEGER NOT NULL DEFAULT 0,
  revoked_at BIGINT,
  revoke_reason VARCHAR(191),
  metadata_json TEXT
);

CREATE INDEX IF NOT EXISTS wrn_auth_sessions_user_idx ON wrn_auth_sessions(user_id);
CREATE INDEX IF NOT EXISTS wrn_auth_sessions_expiry_idx ON wrn_auth_sessions(expires_at);

CREATE TABLE IF NOT EXISTS wrn_auth_trusted_devices (
  id VARCHAR(191) PRIMARY KEY,
  user_id VARCHAR(191) NOT NULL,
  name VARCHAR(191) NOT NULL,
  fingerprint_hash VARCHAR(191) NOT NULL,
  created_at BIGINT NOT NULL,
  last_seen_at BIGINT NOT NULL,
  expires_at BIGINT NOT NULL,
  revoked_at BIGINT,
  UNIQUE(user_id, fingerprint_hash)
);

CREATE TABLE IF NOT EXISTS wrn_auth_tokens (
  id VARCHAR(191) PRIMARY KEY,
  user_id VARCHAR(191) NOT NULL,
  purpose VARCHAR(64) NOT NULL,
  token_hash VARCHAR(191) NOT NULL UNIQUE,
  target VARCHAR(320),
  created_at BIGINT NOT NULL,
  expires_at BIGINT NOT NULL,
  used_at BIGINT,
  attempts INTEGER NOT NULL DEFAULT 0,
  max_attempts INTEGER NOT NULL,
  metadata_json TEXT
);

CREATE INDEX IF NOT EXISTS wrn_auth_tokens_user_idx ON wrn_auth_tokens(user_id);
CREATE INDEX IF NOT EXISTS wrn_auth_tokens_expiry_idx ON wrn_auth_tokens(expires_at);

CREATE TABLE IF NOT EXISTS wrn_auth_otp_challenges (
  id VARCHAR(191) PRIMARY KEY,
  user_id VARCHAR(191) NOT NULL,
  method VARCHAR(32) NOT NULL,
  destination VARCHAR(320) NOT NULL,
  code_hash VARCHAR(191) NOT NULL,
  created_at BIGINT NOT NULL,
  expires_at BIGINT NOT NULL,
  used_at BIGINT,
  attempts INTEGER NOT NULL DEFAULT 0,
  max_attempts INTEGER NOT NULL
);

CREATE TABLE IF NOT EXISTS wrn_auth_totp_credentials (
  id VARCHAR(191) PRIMARY KEY,
  user_id VARCHAR(191) NOT NULL,
  label VARCHAR(191) NOT NULL,
  secret TEXT NOT NULL,
  created_at BIGINT NOT NULL,
  verified_at BIGINT,
  last_counter BIGINT
);

CREATE TABLE IF NOT EXISTS wrn_auth_recovery_codes (
  id VARCHAR(191) PRIMARY KEY,
  user_id VARCHAR(191) NOT NULL,
  code_hash VARCHAR(191) NOT NULL,
  created_at BIGINT NOT NULL,
  used_at BIGINT
);

CREATE INDEX IF NOT EXISTS wrn_auth_recovery_user_idx ON wrn_auth_recovery_codes(user_id);

CREATE TABLE IF NOT EXISTS wrn_auth_passkeys (
  id VARCHAR(191) PRIMARY KEY,
  user_id VARCHAR(191) NOT NULL,
  credential_id TEXT NOT NULL UNIQUE,
  public_key TEXT NOT NULL,
  counter BIGINT NOT NULL DEFAULT 0,
  transports_json TEXT NOT NULL,
  name VARCHAR(191) NOT NULL,
  created_at BIGINT NOT NULL,
  last_used_at BIGINT,
  backed_up INTEGER,
  device_type VARCHAR(64)
);

CREATE INDEX IF NOT EXISTS wrn_auth_passkeys_user_idx ON wrn_auth_passkeys(user_id);

CREATE TABLE IF NOT EXISTS wrn_auth_oauth_accounts (
  id VARCHAR(191) PRIMARY KEY,
  user_id VARCHAR(191) NOT NULL,
  provider VARCHAR(64) NOT NULL,
  provider_account_id VARCHAR(191) NOT NULL,
  email VARCHAR(320),
  access_token TEXT,
  refresh_token TEXT,
  token_expires_at BIGINT,
  scope TEXT,
  created_at BIGINT NOT NULL,
  updated_at BIGINT NOT NULL,
  UNIQUE(provider, provider_account_id)
);

CREATE TABLE IF NOT EXISTS wrn_auth_login_attempts (
  id VARCHAR(191) PRIMARY KEY,
  identifier VARCHAR(320),
  user_id VARCHAR(191),
  success INTEGER NOT NULL,
  reason VARCHAR(191),
  ip VARCHAR(64),
  user_agent TEXT,
  created_at BIGINT NOT NULL,
  risk_score INTEGER NOT NULL,
  risk_level VARCHAR(32) NOT NULL
);

CREATE INDEX IF NOT EXISTS wrn_auth_login_attempts_identifier_idx ON wrn_auth_login_attempts(identifier, created_at);

CREATE TABLE IF NOT EXISTS wrn_auth_security_events (
  id VARCHAR(191) PRIMARY KEY,
  user_id VARCHAR(191),
  type VARCHAR(191) NOT NULL,
  severity VARCHAR(32) NOT NULL,
  actor_user_id VARCHAR(191),
  session_id VARCHAR(191),
  ip VARCHAR(64),
  user_agent TEXT,
  created_at BIGINT NOT NULL,
  data_json TEXT
);

CREATE INDEX IF NOT EXISTS wrn_auth_security_events_user_idx ON wrn_auth_security_events(user_id, created_at);

-- +down
DROP TABLE IF EXISTS wrn_auth_security_events;
DROP TABLE IF EXISTS wrn_auth_login_attempts;
DROP TABLE IF EXISTS wrn_auth_oauth_accounts;
DROP TABLE IF EXISTS wrn_auth_passkeys;
DROP TABLE IF EXISTS wrn_auth_recovery_codes;
DROP TABLE IF EXISTS wrn_auth_totp_credentials;
DROP TABLE IF EXISTS wrn_auth_otp_challenges;
DROP TABLE IF EXISTS wrn_auth_tokens;
DROP TABLE IF EXISTS wrn_auth_trusted_devices;
DROP TABLE IF EXISTS wrn_auth_sessions;
DROP TABLE IF EXISTS wrn_auth_password_credentials;
DROP TABLE IF EXISTS wrn_auth_identities;
DROP TABLE IF EXISTS wrn_auth_users;
