-- migrations/006_create_passkey_tables.sql
-- Passkey (WebAuthn) Authentication Schema

-- Enable UUID extension if not already enabled
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

-- ============================================================================
-- Users Table (if not exists)
-- ============================================================================

CREATE TABLE IF NOT EXISTS users (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  email TEXT UNIQUE,
  username TEXT UNIQUE,
  display_name TEXT,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  last_login_at TIMESTAMPTZ
);

-- ============================================================================
-- Passkeys Table (WebAuthn Credentials)
-- ============================================================================

CREATE TABLE IF NOT EXISTS passkeys (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  credential_id TEXT NOT NULL UNIQUE,
  public_key TEXT NOT NULL,
  sign_count INTEGER NOT NULL DEFAULT 0,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  last_used_at TIMESTAMPTZ,
  device_name TEXT,
  transports TEXT[],  -- USB, NFC, BLE, internal
  aaguid TEXT,
  attestation_format TEXT
);

CREATE INDEX IF NOT EXISTS idx_passkeys_user_id ON passkeys(user_id);
CREATE INDEX IF NOT EXISTS idx_passkeys_credential_id ON passkeys(credential_id);
CREATE INDEX IF NOT EXISTS idx_passkeys_last_used ON passkeys(last_used_at DESC);

-- ============================================================================
-- Sessions Table
-- ============================================================================

CREATE TABLE IF NOT EXISTS sessions (
  token TEXT PRIMARY KEY,
  user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  expires_at TIMESTAMPTZ NOT NULL,
  last_activity_at TIMESTAMPTZ,
  user_agent TEXT,
  ip_address TEXT
);

CREATE INDEX IF NOT EXISTS idx_sessions_user_id ON sessions(user_id);
CREATE INDEX IF NOT EXISTS idx_sessions_expires_at ON sessions(expires_at);

-- ============================================================================
-- Passkey Challenges (temporary, for WebAuthn flow)
-- ============================================================================

CREATE TABLE IF NOT EXISTS passkey_challenges (
  challenge TEXT PRIMARY KEY,
  user_id UUID REFERENCES users(id) ON DELETE CASCADE,
  email TEXT,  -- For registration flow when user doesn't exist yet
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  expires_at TIMESTAMPTZ NOT NULL,
  challenge_type TEXT NOT NULL,  -- 'register' or 'authenticate'
  rp_id TEXT NOT NULL,
  origin TEXT NOT NULL
);

CREATE INDEX IF NOT EXISTS idx_passkey_challenges_expires_at ON passkey_challenges(expires_at);
CREATE INDEX IF NOT EXISTS idx_passkey_challenges_user_id ON passkey_challenges(user_id);

-- ============================================================================
-- User MicroDAO Memberships (for ActorIdentity)
-- ============================================================================

CREATE TABLE IF NOT EXISTS user_microdao_memberships (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  microdao_id TEXT NOT NULL,
  role TEXT NOT NULL,  -- 'owner', 'admin', 'member'
  joined_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  left_at TIMESTAMPTZ,
  
  UNIQUE (user_id, microdao_id)
);

CREATE INDEX IF NOT EXISTS idx_memberships_user_id ON user_microdao_memberships(user_id);
CREATE INDEX IF NOT EXISTS idx_memberships_microdao_id ON user_microdao_memberships(microdao_id);

-- ============================================================================
-- Cleanup Function (remove expired challenges and sessions)
-- ============================================================================

CREATE OR REPLACE FUNCTION cleanup_expired_auth_data()
RETURNS void AS $$
BEGIN
  DELETE FROM passkey_challenges WHERE expires_at < now();
  DELETE FROM sessions WHERE expires_at < now();
END;
$$ LANGUAGE plpgsql;

-- ============================================================================
-- Sample Data (for testing)
-- ============================================================================

-- Create test user
INSERT INTO users (id, email, username, display_name)
VALUES 
  ('00000000-0000-0000-0000-000000000001', 'admin@daarion.city', 'admin', 'Admin User'),
  ('00000000-0000-0000-0000-000000000093', 'user93@daarion.city', 'user93', 'User 93')
ON CONFLICT (email) DO NOTHING;

-- Add microDAO memberships
INSERT INTO user_microdao_memberships (user_id, microdao_id, role)
VALUES
  ('00000000-0000-0000-0000-000000000001', 'microdao:daarion', 'owner'),
  ('00000000-0000-0000-0000-000000000093', 'microdao:7', 'owner'),
  ('00000000-0000-0000-0000-000000000093', 'microdao:daarion', 'member')
ON CONFLICT (user_id, microdao_id) DO NOTHING;

-- ============================================================================
-- Triggers for updated_at
-- ============================================================================

CREATE OR REPLACE FUNCTION update_timestamp()
RETURNS TRIGGER AS $$
BEGIN
  NEW.updated_at = now();
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER set_users_timestamp
BEFORE UPDATE ON users
FOR EACH ROW
EXECUTE FUNCTION update_timestamp();
















