-- La venta offline del Cerebrito tambien lleva su desglose (2026-07-28).
-- El calculo lo hace la BD, no la laptop: la alicuota vive aca.
begin;

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;
  v_alic_rest numeric(5,2);
  v_con_iva boolean;
  v_alic numeric(5,2);
  v_linea numeric(10,2);
  v_base_linea numeric(10,2);
  v_iva_linea numeric(10,2);
  v_base_total numeric(10,2);
  v_iva_total numeric(10,2);
begin
  select coalesce(r.iva_alicuota, 16), coalesce(r.precios_con_iva, true)
    into v_alic_rest, v_con_iva
    from public.restaurantes r where r.id = v_rest;
  v_alic_rest := coalesce(v_alic_rest, 16);
  v_con_iva := coalesce(v_con_iva, true);
  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;

    -- IMPUESTO de la venta offline: lo calcula la BD, no la laptop (la alicuota
    -- vive aca). Mismo criterio que crear_pedido.
    v_base_total := 0;
    v_iva_total := 0;
    for v_item in select * from jsonb_array_elements(coalesce(v_ped->'items', '[]'::jsonb)) loop
      select coalesce(pr.iva_alicuota, v_alic_rest) into v_alic
        from public.productos pr where pr.id = nullif(v_item->>'producto_id', '')::uuid;
      v_alic := coalesce(v_alic, v_alic_rest);
      v_linea := round(coalesce((v_item->>'precio_usd')::numeric, 0) * greatest(coalesce((v_item->>'cantidad')::int, 1), 1), 2);
      if v_con_iva then
        v_base_linea := round(v_linea / (1 + v_alic / 100), 2);
        v_iva_linea := v_linea - v_base_linea;
      else
        v_base_linea := v_linea;
        v_iva_linea := round(v_linea * v_alic / 100, 2);
      end if;
      v_base_total := v_base_total + v_base_linea;
      v_iva_total := v_iva_total + v_iva_linea;
      insert into public.pedido_items (id, pedido_id, producto_id, nombre, precio_usd, cantidad, nota, iva_alicuota, base_usd, iva_usd)
      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', ''),
        v_alic, v_base_linea, v_iva_linea
      )
      on conflict (id) do nothing;
    end loop;
    update public.pedidos
       set base_imponible_usd = v_base_total, iva_usd = v_iva_total, iva_alicuota = v_alic_rest
     where id = (v_ped->>'id')::uuid and base_imponible_usd is null;
  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$
;

commit;
