-- ETAPA 2 del cerebrito (blindaje offline): el salon puede operar SIN internet
-- en la laptop del local y sincronizar al volver.
--  (1) cerebritos: latido de cada laptop (base del tablero central y de la
--      futura pausa suave del QR).
--  (2) sincronizar_venta_local: sube una venta COMPLETA hecha offline (cuenta
--      de mesa cerrada o venta directa) de forma IDEMPOTENTE (reintentos y
--      duplicados no crean filas de mas). La serie local usa codigo
--      "{prefijo}-L{n}" que no choca con el contador de la nube.

create table if not exists public.cerebritos (
  restaurante_id uuid primary key references public.restaurantes(id) on delete cascade,
  visto_en timestamptz not null default now(),
  version text,
  detalle jsonb
);

comment on table public.cerebritos is
  'Latido de la laptop (cerebrito) de cada negocio: cuando se vio por ultima vez y como esta.';

alter table public.cerebritos enable row level security;

create policy cerebritos_select on public.cerebritos
  for select to authenticated
  using (public.fn_es_staff_de(restaurante_id) or public.fn_es_admin());

-- La escritura va SOLO por la RPC del latido (valida el rol adentro).

create or replace function public.fn_cerebrito_latido(p_version text default null, p_detalle jsonb default null)
 returns void
 language plpgsql
 security definer
 set search_path to 'public'
as $function$
declare v_rest uuid := fn_mi_restaurante();
begin
  if v_rest is null or not fn_es_staff_de(v_rest) then
    raise exception 'Sin permiso';
  end if;
  insert into public.cerebritos (restaurante_id, visto_en, version, detalle)
  values (v_rest, now(), p_version, p_detalle)
  on conflict (restaurante_id) do update
    set visto_en = now(),
        version = coalesce(excluded.version, cerebritos.version),
        detalle = coalesce(excluded.detalle, cerebritos.detalle);
end;
$function$;

create or replace function public.sincronizar_venta_local(p_venta jsonb)
 returns jsonb
 language plpgsql
 security definer
 set search_path to 'public'
as $function$
declare
  v_rest uuid := fn_mi_restaurante();
  v_cuenta_id uuid;
  v_ped jsonb;
  v_item jsonb;
  v_pago jsonb;
  v_rc integer;
  n_pedidos integer := 0;
  n_pagos integer := 0;
begin
  if v_rest is null or not fn_es_staff_de(v_rest) then
    raise exception 'Sin permiso';
  end if;

  -- Cuenta de mesa (solo en ventas de salon); llega YA cerrada.
  if p_venta ? 'cuenta' then
    v_cuenta_id := (p_venta->'cuenta'->>'id')::uuid;
    insert into public.cuentas_mesa (id, restaurante_id, mesa, estado, abierta_en, cerrada_en, mesero_nombre)
    values (
      v_cuenta_id,
      v_rest,
      p_venta->'cuenta'->>'mesa',
      'cerrada',
      coalesce((p_venta->'cuenta'->>'abierta_en')::timestamptz, now()),
      coalesce((p_venta->'cuenta'->>'cerrada_en')::timestamptz, now()),
      nullif(p_venta->'cuenta'->>'mesero_nombre', '')
    )
    on conflict (id) do nothing;
  end if;

  for v_ped in select * from jsonb_array_elements(coalesce(p_venta->'pedidos', '[]'::jsonb)) loop
    insert into public.pedidos (
      id, restaurante_id, codigo, cliente_nombre, cliente_telefono, tipo_entrega, mesa, para_llevar,
      estado, metodo_pago, nota, subtotal_usd, total_usd, tasa_bs, cuenta_id, mesero_nombre,
      recibido_en, confirmado_en, entregado_en
    )
    values (
      (v_ped->>'id')::uuid,
      v_rest,
      v_ped->>'codigo',
      coalesce(nullif(v_ped->>'cliente_nombre', ''), 'Cliente'),
      '',
      coalesce(nullif(v_ped->>'tipo_entrega', ''), 'mesa'),
      nullif(v_ped->>'mesa', ''),
      coalesce((v_ped->>'para_llevar')::boolean, false),
      'entregado',
      nullif(v_ped->>'metodo_pago', ''),
      nullif(v_ped->>'nota', ''),
      coalesce((v_ped->>'subtotal_usd')::numeric, 0),
      coalesce((v_ped->>'total_usd')::numeric, 0),
      nullif(v_ped->>'tasa_bs', '')::numeric,
      v_cuenta_id,
      nullif(v_ped->>'mesero_nombre', ''),
      coalesce((v_ped->>'recibido_en')::timestamptz, now()),
      coalesce((v_ped->>'confirmado_en')::timestamptz, now()),
      coalesce((v_ped->>'entregado_en')::timestamptz, now())
    )
    on conflict (id) do nothing;
    get diagnostics v_rc = row_count;
    n_pedidos := n_pedidos + v_rc;

    for v_item in select * from jsonb_array_elements(coalesce(v_ped->'items', '[]'::jsonb)) loop
      insert into public.pedido_items (id, pedido_id, producto_id, nombre, precio_usd, cantidad, nota)
      values (
        (v_item->>'id')::uuid,
        (v_ped->>'id')::uuid,
        nullif(v_item->>'producto_id', '')::uuid,
        v_item->>'nombre',
        coalesce((v_item->>'precio_usd')::numeric, 0),
        greatest(coalesce((v_item->>'cantidad')::int, 1), 1),
        nullif(v_item->>'nota', '')
      )
      on conflict (id) do nothing;
    end loop;
  end loop;

  for v_pago in select * from jsonb_array_elements(coalesce(p_venta->'pagos', '[]'::jsonb)) loop
    if v_cuenta_id is not null then
      insert into public.pagos_mesa (id, cuenta_id, restaurante_id, monto_usd, metodo, referencia, propina_usd, verificado, mesero_nombre)
      values (
        (v_pago->>'id')::uuid,
        v_cuenta_id,
        v_rest,
        coalesce((v_pago->>'monto_usd')::numeric, 0),
        coalesce(nullif(v_pago->>'metodo', ''), 'efectivo'),
        nullif(v_pago->>'referencia', ''),
        nullif(v_pago->>'propina_usd', '')::numeric,
        coalesce(nullif(v_pago->>'metodo', ''), 'efectivo') = 'efectivo',
        nullif(v_pago->>'mesero_nombre', '')
      )
      on conflict (id) do nothing;
    else
      insert into public.pagos (id, pedido_id, metodo, monto_usd, referencia, estado)
      values (
        (v_pago->>'id')::uuid,
        (v_pago->>'pedido_id')::uuid,
        coalesce(nullif(v_pago->>'metodo', ''), 'efectivo'),
        coalesce((v_pago->>'monto_usd')::numeric, 0),
        nullif(v_pago->>'referencia', ''),
        'confirmado'
      )
      on conflict (id) do nothing;
    end if;
    get diagnostics v_rc = row_count;
    n_pagos := n_pagos + v_rc;
  end loop;

  return jsonb_build_object('ok', true, 'pedidos_nuevos', n_pedidos, 'pagos_nuevos', n_pagos);
end;
$function$;

-- Solo usuarios del negocio (validado adentro); nada de anon.
revoke all on function public.fn_cerebrito_latido(text, jsonb) from public, anon;
revoke all on function public.sincronizar_venta_local(jsonb) from public, anon;
grant execute on function public.fn_cerebrito_latido(text, jsonb) to authenticated;
grant execute on function public.sincronizar_venta_local(jsonb) to authenticated;
