drop function if exists medreport.add_invitations_to_account(text, medreport.invitation[]);

drop type if exists medreport.invitation;

create type medreport.invitation as (
  email text,
  role text,
  personal_code char(11)
);

create or replace function medreport.add_invitations_to_account (
    account_slug text,
    invitations medreport.invitation[]
) returns medreport.invitations[]
    set search_path = ''
as $$
declare
    new_invitation medreport.invitations;
    all_invitations medreport.invitations[] := array[]::medreport.invitations[];
    invite_token text;
    invite medreport.invitation;
begin
    foreach invite in array invitations loop
        invite_token := extensions.uuid_generate_v4();

        insert into medreport.invitations (
            email,
            account_id,
            invited_by,
            role,
            invite_token,
            personal_code
        )
        values (
            invite.email,
            (select id from medreport.accounts where slug = account_slug),
            auth.uid(),
            invite.role,
            invite_token,
            invite.personal_code
        )
        returning * into new_invitation;

        all_invitations := array_append(all_invitations, new_invitation);
    end loop;

    return all_invitations;
end;
$$ language plpgsql;

grant execute on function medreport.add_invitations_to_account(text, medreport.invitation[]) to authenticated;

grant
    execute on function medreport.has_permission (uuid, uuid, medreport.app_permissions) to authenticated,
    service_role;

grant
    execute on function medreport.has_more_elevated_role (uuid, uuid, varchar) to authenticated,
    service_role;

grant
    execute on function medreport.has_same_role_hierarchy_level (uuid, uuid, varchar) to authenticated,
    service_role;

ALTER TABLE medreport.invitations ALTER COLUMN id DROP DEFAULT;
ALTER TABLE medreport.invitations DROP COLUMN id;
ALTER TABLE medreport.invitations ADD COLUMN id UUID NOT NULL DEFAULT gen_random_uuid();
ALTER TABLE medreport.invitations ADD PRIMARY KEY (id);

ALTER TABLE medreport.invitations DROP CONSTRAINT invitations_pkey;
ALTER TABLE medreport.invitations DROP COLUMN id;

ALTER TABLE medreport.invitations ADD COLUMN id SERIAL PRIMARY KEY;

DROP FUNCTION IF EXISTS medreport.get_account_invitations(account_slug text);

create function medreport.get_account_invitations (account_slug text)
returns table (
  id integer,
  email varchar(255),
  account_id uuid,
  invited_by uuid,
  role varchar(50),
  created_at timestamptz,
  updated_at timestamptz,
  expires_at timestamptz,
  personal_code text,
  inviter_name varchar,
  inviter_email varchar
)
set search_path = ''
as $$
begin
  return query
    select
      invitation.id,
      invitation.email,
      invitation.account_id,
      invitation.invited_by,
      invitation.role,
      invitation.created_at,
      invitation.updated_at,
      invitation.expires_at,
      invitation.personal_code,
      account.name,
      account.email
    from
      medreport.invitations as invitation
      join medreport.accounts as account on invitation.account_id = account.id
    where
      account.slug = account_slug;
end;
$$ language plpgsql;

grant execute on function medreport.get_account_invitations(text) to authenticated, service_role;


drop policy if exists invitations_read_self on medreport.invitations;
drop policy if exists invitations_create_self on medreport.invitations;
drop policy if exists invitations_update on medreport.invitations;
drop policy if exists invitations_delete on medreport.invitations;
drop policy if exists super_admins_access_invitations on medreport.invitations;


create policy invitations_read_self on medreport.invitations for
    select
    to authenticated using (medreport.has_role_on_account (account_id));

create policy invitations_create_self on medreport.invitations for insert to authenticated
    with
    check (
        medreport.is_set ('enable_team_accounts')
        and medreport.has_permission (
                (
                    select
                        auth.uid ()
                ),
                account_id,
                'invites.manage'::medreport.app_permissions
            )
        and (medreport.has_more_elevated_role (
                     (
                         select
                             auth.uid ()
                     ),
                     account_id,
                     role
                 ) or medreport.has_same_role_hierarchy_level(
                     (
                         select
                             auth.uid ()
                     ),
                     account_id,
                     role
                 ))
    );

create policy invitations_update on medreport.invitations
    for update
    to authenticated using (
        medreport.has_permission (
                (
                    select
                        auth.uid ()
                ),
                account_id,
                'invites.manage'::medreport.app_permissions
            )
        and medreport.has_more_elevated_role (
                (
                    select
                        auth.uid ()
                ),
                account_id,
                role
            )
    )
    with
    check (
        medreport.has_permission (
                (
                    select
                        auth.uid ()
                ),
                account_id,
                'invites.manage'::medreport.app_permissions
            )
        and medreport.has_more_elevated_role (
                (
                    select
                        auth.uid ()
                ),
                account_id,
                role
            )
    );

create policy invitations_delete on medreport.invitations for delete to authenticated using (
        medreport.has_role_on_account (account_id)
        and medreport.has_permission (
                (
                    select
                        auth.uid ()
                ),
                account_id,
                'invites.manage'::medreport.app_permissions
            )
    );

create policy super_admins_access_invitations
    on medreport.invitations
    as permissive
    for select
    to authenticated
    using (medreport.is_super_admin());

INSERT INTO medreport.config DEFAULT VALUES;

DROP FUNCTION public.get_invitations_with_account_ids(
  company_id uuid,
  personal_codes text[]
);

ALTER TABLE "medreport"."invitations" ADD COLUMN IF NOT EXISTS personal_code text;

DO $$
BEGIN
  IF NOT EXISTS (
    SELECT 1
    FROM pg_constraint
    WHERE conname = 'accounts_personal_code_unique'
  ) THEN
    ALTER TABLE medreport.accounts
    ADD CONSTRAINT accounts_personal_code_unique UNIQUE (personal_code);
  END IF;
END$$;

ALTER TABLE medreport.invitations
ALTER COLUMN personal_code TYPE text;

DO $$
BEGIN
  IF NOT EXISTS (
    SELECT 1
    FROM pg_constraint
    WHERE conname = 'invitations_personal_code_unique'
  ) THEN
    ALTER TABLE medreport.invitations
    ADD CONSTRAINT invitations_personal_code_unique UNIQUE (personal_code);
  END IF;
END$$;

create or replace function medreport.get_invitations_with_account_ids(
  company_id uuid,
  personal_codes text[]
)
returns table (
  invite_token text,
  personal_code text,
  account_id uuid
)
language sql
as $$
  select
    i.invite_token,
    i.personal_code,
    a.id as account_id
  from medreport.invitations i
  join medreport.accounts a on a.personal_code = i.personal_code
  where  i.account_id = company_id 
  and i.personal_code = any(personal_codes);
$$;

grant
    execute on function medreport.get_invitations_with_account_ids (uuid, text[]) to authenticated,
    service_role;

GRANT USAGE, SELECT ON SEQUENCE medreport.invitations_id_seq TO authenticated;

DROP FUNCTION IF EXISTS public.has_permission(uuid, uuid, medreport.app_permissions);