CREATE TABLE users (
  id UUID PRIMARY KEY,
  status VARCHAR(16) NOT NULL DEFAULT 'active'
    CHECK (status IN ('active', 'disabled')),
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

INSERT INTO users (id)
SELECT owner_id FROM student_profiles
UNION
SELECT owner_id FROM student_profile_defaults
UNION
SELECT owner_id FROM feedback_records
UNION
SELECT owner_id FROM feedback_sessions
ON CONFLICT (id) DO NOTHING;

CREATE TABLE wechat_identities (
  app_id VARCHAR(64) NOT NULL,
  openid VARCHAR(128) NOT NULL,
  unionid VARCHAR(128),
  user_id UUID NOT NULL REFERENCES users(id) ON DELETE RESTRICT,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  last_login_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  PRIMARY KEY (app_id, openid)
);

CREATE INDEX wechat_identities_user_idx
  ON wechat_identities (user_id);

CREATE UNIQUE INDEX wechat_identities_app_unionid_idx
  ON wechat_identities (app_id, unionid)
  WHERE unionid IS NOT NULL;

CREATE TABLE auth_sessions (
  id UUID PRIMARY KEY,
  user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  token_hash BYTEA NOT NULL UNIQUE CHECK (octet_length(token_hash) = 32),
  expires_at TIMESTAMPTZ NOT NULL,
  last_used_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  revoked_at TIMESTAMPTZ,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX auth_sessions_active_user_idx
  ON auth_sessions (user_id, expires_at DESC)
  WHERE revoked_at IS NULL;

ALTER TABLE student_profiles
  ADD CONSTRAINT student_profiles_owner_fk
  FOREIGN KEY (owner_id) REFERENCES users(id) ON DELETE RESTRICT;

ALTER TABLE student_profile_defaults
  ADD CONSTRAINT student_profile_defaults_owner_fk
  FOREIGN KEY (owner_id) REFERENCES users(id) ON DELETE RESTRICT;

ALTER TABLE feedback_records
  ADD CONSTRAINT feedback_records_owner_fk
  FOREIGN KEY (owner_id) REFERENCES users(id) ON DELETE RESTRICT;

ALTER TABLE feedback_sessions
  ADD CONSTRAINT feedback_sessions_owner_fk
  FOREIGN KEY (owner_id) REFERENCES users(id) ON DELETE RESTRICT;
