/*
  patient_groups_setup.sql
  Setup completo para:
  - public.patient_groups
  - public.patient_group_patient (tabela ponte)
  - view public.v_patient_groups_with_counts
  - índice único por owner + nome (case-insensitive)
  - 3 grupos padrão do sistema (Crianças, Adolescentes, Idosos) NÃO editáveis / NÃO removíveis
  - triggers de proteção

  Observação (importante):
  - Os grupos padrão são criados com owner_id = '00000000-0000-0000-0000-000000000000' (SYSTEM_OWNER),
    para ficarem "globais" e não dependerem de auth.uid() em migrations.
  - Se você quiser que os grupos padrão pertençam a um owner específico (tenant),
    basta trocar o SYSTEM_OWNER abaixo por esse UUID.
*/

begin;

-- ===========================
-- 0) Constante de "dono do sistema"
-- ===========================
-- Troque aqui se você quiser que os grupos padrão pertençam a um owner específico.
-- Ex.: '816b24fe-a0c3-4409-b79b-c6c0a6935d03'
do $$
begin
  -- só para documentar; não cria nada
end $$;

-- ===========================
-- 1) Tabela principal: patient_groups
-- ===========================
create table if not exists public.patient_groups (
  id uuid primary key default gen_random_uuid(),
  name text not null,
  description text,
  color text,
  is_active boolean not null default true,
  is_system boolean not null default false,
  owner_id uuid not null,
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now()
);

-- (Opcional, mas recomendado) Garante que name não seja só espaços
-- e evita nomes vazios.
alter table public.patient_groups
  drop constraint if exists patient_groups_name_not_blank_check;

alter table public.patient_groups
  add constraint patient_groups_name_not_blank_check
  check (length(btrim(name)) > 0);

-- ===========================
-- 2) Tabela ponte: patient_group_patient
-- ===========================
-- Se você já tiver essa tabela com FKs, ajuste aqui conforme seu schema.
create table if not exists public.patient_group_patient (
  patient_group_id uuid not null references public.patient_groups(id) on delete cascade,
  patient_id uuid not null references public.patients(id) on delete cascade,
  created_at timestamptz not null default now()
);

-- Evita duplicar vínculo paciente<->grupo
create unique index if not exists patient_group_patient_unique
on public.patient_group_patient (patient_group_id, patient_id);

-- ===========================
-- 3) View com contagem
-- ===========================
create or replace view public.v_patient_groups_with_counts as
select
  g.*,
  coalesce(count(distinct pgp.patient_id), 0)::int as patients_count
from public.patient_groups g
left join public.patient_group_patient pgp
  on pgp.patient_group_id = g.id
group by g.id;

-- ===========================
-- 4) Índice único: não permitir mesmo nome por owner (case-insensitive)
-- ===========================
-- Atenção: se já existirem duplicados, este índice pode falhar ao criar.
create unique index if not exists patient_groups_owner_name_unique
on public.patient_groups (owner_id, (lower(name)));

-- ===========================
-- 5) Triggers de proteção: system não edita / não remove
-- ===========================
create or replace function public.prevent_system_group_changes()
returns trigger
language plpgsql
as $$
begin
  if old.is_system = true then
    raise exception 'Grupos padrão do sistema não podem ser alterados ou excluídos.';
  end if;

  if tg_op = 'DELETE' then
    return old;
  end if;

  return new;
end;
$$;

drop trigger if exists trg_prevent_system_group_changes on public.patient_groups;

create trigger trg_prevent_system_group_changes
before update or delete on public.patient_groups
for each row
execute function public.prevent_system_group_changes();

-- Impede "promover" um grupo comum para system
create or replace function public.prevent_promoting_to_system()
returns trigger
language plpgsql
as $$
begin
  if new.is_system = true and old.is_system is distinct from true then
    raise exception 'Não é permitido transformar um grupo comum em grupo do sistema.';
  end if;
  return new;
end;
$$;

drop trigger if exists trg_prevent_promoting_to_system on public.patient_groups;

create trigger trg_prevent_promoting_to_system
before update on public.patient_groups
for each row
execute function public.prevent_promoting_to_system();

-- ===========================
-- 6) Inserir 3 grupos padrão (imutáveis)
-- ===========================
-- Dono "global" do sistema (mude se quiser):
-- 00000000-0000-0000-0000-000000000000
with sys_owner as (
  select '00000000-0000-0000-0000-000000000000'::uuid as owner_id
)
insert into public.patient_groups (name, description, color, is_active, is_system, owner_id)
select v.name, v.description, v.color, v.is_active, v.is_system, s.owner_id
from sys_owner s
join (values
  ('Crianças',     'Grupo padrão do sistema', null, true, true),
  ('Adolescentes', 'Grupo padrão do sistema', null, true, true),
  ('Idosos',       'Grupo padrão do sistema', null, true, true)
) as v(name, description, color, is_active, is_system)
on true
where not exists (
  select 1
  from public.patient_groups g
  where g.owner_id = s.owner_id
    and lower(g.name) = lower(v.name)
);

commit;

/*
  Testes rápidos:
  1) Ver tudo:
     select * from public.v_patient_groups_with_counts order by is_system desc, name;

  2) Tentar editar um system (deve falhar):
     update public.patient_groups set name='X' where name='Crianças';

  3) Tentar deletar um system (deve falhar):
     delete from public.patient_groups where name='Crianças';

  4) Tentar duplicar nome no mesmo owner (deve falhar por índice único):
     insert into public.patient_groups (name, is_active, is_system, owner_id)
     values ('teste22', true, false, '816b24fe-a0c3-4409-b79b-c6c0a6935d03');
*/
