CREATE TABLE IF NOT EXISTS users (
  id SERIAL PRIMARY KEY,
  email TEXT UNIQUE NOT NULL,
  display_name TEXT,
  avatar_url TEXT,
  role TEXT DEFAULT 'member' CHECK (role IN ('admin', 'member')),
  gitea_username TEXT,
  github_login TEXT,
  password_hash TEXT,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  last_seen_at TIMESTAMPTZ
);

CREATE TABLE IF NOT EXISTS organizations (
  id SERIAL PRIMARY KEY,
  slug TEXT UNIQUE NOT NULL,
  name TEXT NOT NULL,
  description TEXT,
  shared_password_hash TEXT,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS organization_members (
  organization_id INT NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
  user_id INT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  role TEXT NOT NULL DEFAULT 'member' CHECK (role IN ('owner', 'admin', 'member')),
  created_at TIMESTAMPTZ DEFAULT NOW(),
  PRIMARY KEY (organization_id, user_id)
);

CREATE INDEX IF NOT EXISTS idx_org_members_user ON organization_members(user_id);

CREATE TABLE IF NOT EXISTS audit_log (
  id BIGSERIAL PRIMARY KEY,
  user_id INT REFERENCES users(id),
  action TEXT NOT NULL,
  target TEXT,
  metadata JSONB,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_audit_log_user ON audit_log(user_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_audit_log_action ON audit_log(action, created_at DESC);

CREATE TABLE IF NOT EXISTS portal_pages (
  id SERIAL PRIMARY KEY,
  slug TEXT UNIQUE NOT NULL,
  title TEXT NOT NULL,
  content TEXT,
  source_repo TEXT,
  source_path TEXT,
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS infra_tokens (
  id SERIAL PRIMARY KEY,
  name TEXT NOT NULL,
  service TEXT NOT NULL,
  location TEXT NOT NULL,
  env_var_name TEXT,
  expires_at TIMESTAMPTZ,
  last_rotated_at TIMESTAMPTZ,
  machines TEXT[] DEFAULT '{}',
  notes TEXT,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS infra_services (
  id SERIAL PRIMARY KEY,
  name TEXT NOT NULL,
  url TEXT,
  tailscale_ip TEXT,
  health_endpoint TEXT,
  last_check_at TIMESTAMPTZ,
  last_status TEXT DEFAULT 'unknown' CHECK (last_status IN ('ok', 'error', 'timeout', 'unknown')),
  cost_monthly TEXT,
  provider TEXT,
  notes TEXT,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_infra_tokens_service ON infra_tokens(service);
CREATE INDEX IF NOT EXISTS idx_infra_tokens_expires ON infra_tokens(expires_at);
CREATE INDEX IF NOT EXISTS idx_infra_services_status ON infra_services(last_status);

-- Gateway merge (see db/migrations/004_gateway.sql)
CREATE TABLE IF NOT EXISTS gateway_votes (
  user_email TEXT NOT NULL,
  slug TEXT NOT NULL,
  item_id TEXT NOT NULL,
  voted_at TIMESTAMPTZ DEFAULT NOW(),
  PRIMARY KEY (user_email, slug, item_id)
);

CREATE TABLE IF NOT EXISTS gateway_reads (
  id SERIAL PRIMARY KEY,
  user_email TEXT NOT NULL,
  slug TEXT NOT NULL,
  reaction TEXT NOT NULL,
  read_at TIMESTAMPTZ DEFAULT NOW(),
  UNIQUE (user_email, slug, reaction)
);

CREATE TABLE IF NOT EXISTS gateway_agents (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id TEXT NOT NULL,
  title TEXT NOT NULL DEFAULT 'New chat',
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS gateway_agent_messages (
  id TEXT PRIMARY KEY,
  agent_id UUID NOT NULL REFERENCES gateway_agents(id) ON DELETE CASCADE,
  role TEXT NOT NULL CHECK (role IN ('user', 'assistant', 'system')),
  parts JSONB NOT NULL DEFAULT '[]',
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_gateway_agent_messages_agent ON gateway_agent_messages(agent_id);

CREATE TABLE IF NOT EXISTS sentinel_kv (
  key TEXT PRIMARY KEY,
  value JSONB NOT NULL,
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS sentinel_telemetry (
  id BIGSERIAL PRIMARY KEY,
  ts TIMESTAMPTZ NOT NULL,
  model TEXT NOT NULL,
  tier TEXT NOT NULL,
  input_tokens INT NOT NULL,
  output_tokens INT NOT NULL,
  cost_usd DOUBLE PRECISION NOT NULL,
  duration_ms INT NOT NULL,
  action TEXT NOT NULL,
  escalated BOOLEAN NOT NULL DEFAULT FALSE,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_sentinel_telemetry_ts ON sentinel_telemetry(ts DESC);
