create type public.usr_username as (username text);

create table public.usr_audit
  ( usr           int                 not null
  , kind          public.audit_kind   not null
  , actor         int                 not null
  , prev_username public.usr_username null
  , prev_password public.hashed_text  null
  , prev_email    public.email        null
  );

create table public.usr
  ( id       int                 not null primary key generated always as identity
  , uid      uuid                not null default gen_random_uuid()
  , deleted  boolean             not null default false
  , username public.usr_username not null unique
  , password public.hashed_text  not null
  , email    public.email        not null unique
  );

alter table public.usr_audit
  add constraint fk_usr_audit_usr
  foreign key (usr)
  references public.usr (id)
, add constraint fk_usr_audit_actor
  foreign key (actor)
  references public.usr (id)
;

create function public.do_usr_audit()
  returns trigger
  language plpgsql as $$
  declare
    audit_kind public.audit_kind;
    usr_id int;
    prev_username public.usr_username := null;
    prev_password public.hashed_text   := null;
    prev_email    public.email         := null;
  begin
    if (TG_OP = 'UPDATE') then
      usr_id := OLD.id;
      audit_kind := 'modify';
      prev_username := OLD.username;
      prev_password := OLD.password;
      prev_email := OLD.email;
    elsif (TG_OP = 'INSERT') then
      usr_id := NEW.id;
      audit_kind := 'create';
    end if;

    insert into public.usr_audit
      (kind, usr, actor, prev_username, prev_email, prev_password )
    values
      -- TODO actor
      (audit_kind, usr_id, usr_id, prev_username, prev_email, prev_password );

    return NEW;
  end;
$$;

create function public.do_usr_soft_delete()
  returns trigger
  language plpgsql as $$
  declare
    audit_id int;
  begin
    insert into public.usr_audit
      (kind, usr, actor)
    values
      -- TODO actor
      ('delete' :: public.audit_kind, OLD.id, OLD.id);

    update public.usr
    set deleted = true
    where id = OLD.id;

    return null;
  end;
$$;

create trigger trigger_usr_audit
  after insert or update on public.usr
  for each row execute function public.do_usr_audit();

create trigger trigger_usr_soft_delete
  before delete on public.usr
  for each row execute function public.do_usr_soft_delete();
