-- Migration: flatten ALL products from source_orders into simple orderItems list
-- This replaces the previous nested orderItems building section.

CREATE OR REPLACE FUNCTION public.get_delivery_invitation_by_token(p_token text)
RETURNS jsonb
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public, extensions
AS $$
DECLARE
  v_invitation public.delivery_invitations%rowtype;
  v_group public.order_groups%rowtype;
  v_order record;
  v_token_hash text;
  v_state text;
  v_order_number text;
  v_customer_name text;
  v_customer_phone text;
  v_order_items jsonb;
  v_now timestamptz := timezone('utc', now());
BEGIN
  IF nullif(trim(coalesce(p_token, '')), '') IS NULL THEN
    RAISE EXCEPTION 'token is required';
  END IF;

  v_token_hash := encode(digest(p_token, 'sha256'), 'hex');

  SELECT *
  INTO v_invitation
  FROM public.delivery_invitations
  WHERE token_hash = v_token_hash;

  IF NOT found THEN
    RAISE EXCEPTION 'Invitation not found';
  END IF;

  IF v_invitation.revoked_at IS NOT NULL THEN
    RAISE EXCEPTION 'Invitation expired';
  END IF;

  IF v_invitation.expires_at IS NOT NULL AND v_invitation.expires_at <= v_now THEN
    RAISE EXCEPTION 'Invitation expired';
  END IF;

  IF v_invitation.order_group_id IS NOT NULL THEN
    SELECT *
    INTO v_group
    FROM public.order_groups
    WHERE id = v_invitation.order_group_id;

    IF NOT found THEN
      RAISE EXCEPTION 'Order group not found';
    END IF;

    v_state := CASE
      WHEN v_group.delivery_status = 'agreed' THEN 'agreed'
      WHEN v_group.delivery_status = 'delivered' THEN 'delivered'
      WHEN v_invitation.state IN ('awaiting_choice', 'opened', 'reminder_sent') THEN v_invitation.state
      ELSE 'default'
    END;

    UPDATE public.delivery_invitations
    SET
      opened_at = CASE
        WHEN v_state IN ('awaiting_choice', 'opened', 'reminder_sent') AND opened_at IS NULL THEN v_now
        ELSE opened_at
      END,
      access_count = COALESCE(access_count, 0) + 1,
      last_accessed_at = v_now
    WHERE id = v_invitation.id
    RETURNING * INTO v_invitation;

    v_order_number := COALESCE(
      NULLIF(v_invitation.order_number, ''),
      to_jsonb(v_group.order_numbers) ->> 0,
      NULLIF(v_group.group_key, '')
    );
    v_customer_name := COALESCE(
      NULLIF(v_group.customer_name, ''),
      NULLIF(v_invitation.customer_name, '')
    );
    v_customer_phone := COALESCE(
      NULLIF(v_group.customer_phone, ''),
      NULLIF(v_group.customer_phone_normalized, ''),
      NULLIF(v_invitation.customer_phone, '')
    );

    -- Build orderItems: flatten ALL products from source_orders into a flat list.
    -- Strategy 1: products inside orderList[].items[]
    -- Strategy 2: products inside items[] directly on source_orders entry
    -- Strategy 3: fallback to invoice names from order_numbers
    v_order_items := CASE
      WHEN v_group.source_orders IS NOT NULL
        AND jsonb_typeof(v_group.source_orders) = 'array'
        AND jsonb_array_length(v_group.source_orders) > 0
      THEN COALESCE(
        -- Strategy 1: flatten products from orderList[].items[]
        (SELECT jsonb_agg(
          jsonb_build_object(
            'name', p ->> 'product_name',
            'quantity', COALESCE(NULLIF(p ->> 'product_quantity', ''), ''),
            'unit', COALESCE(NULLIF(p ->> 'product_ed', ''), '')
          )
        )
        FROM jsonb_array_elements(v_group.source_orders) AS src,
             LATERAL jsonb_array_elements(
               CASE
                 WHEN jsonb_typeof(src -> 'orderList') = 'array' THEN src -> 'orderList'
                 ELSE '[]'::jsonb
               END
             ) AS so,
             LATERAL jsonb_array_elements(
               CASE
                 WHEN jsonb_typeof(so -> 'items') = 'array' THEN so -> 'items'
                 ELSE '[]'::jsonb
               END
             ) AS p
        WHERE p ->> 'product_name' IS NOT NULL
          AND p ->> 'product_name' != ''),

        -- Strategy 2: products inside items[] directly on source_orders entry
        (SELECT jsonb_agg(
          jsonb_build_object(
            'name', p ->> 'product_name',
            'quantity', COALESCE(NULLIF(p ->> 'product_quantity', ''), ''),
            'unit', COALESCE(NULLIF(p ->> 'product_ed', ''), '')
          )
        )
        FROM jsonb_array_elements(v_group.source_orders) AS src,
             LATERAL jsonb_array_elements(
               CASE
                 WHEN jsonb_typeof(src -> 'items') = 'array' THEN src -> 'items'
                 ELSE '[]'::jsonb
               END
             ) AS p
        WHERE p ->> 'product_name' IS NOT NULL
          AND p ->> 'product_name' != ''
          AND NOT (p ? 'nom' AND p ? 'items')),  -- exclude sub-order entries

        -- Strategy 3: fallback to invoice names
        (SELECT jsonb_agg(jsonb_build_object('name', on_num, 'quantity', ''))
         FROM jsonb_array_elements_text(
           CASE
             WHEN jsonb_typeof(to_jsonb(v_group.order_numbers)) = 'array' THEN to_jsonb(v_group.order_numbers)
             ELSE '[]'::jsonb
           END
         ) AS on_num),

        '[]'::jsonb
      )
      ELSE COALESCE(
        (SELECT jsonb_agg(jsonb_build_object('name', order_number, 'quantity', ''))
         FROM jsonb_array_elements_text(
           CASE
             WHEN jsonb_typeof(to_jsonb(v_group.order_numbers)) = 'array' THEN to_jsonb(v_group.order_numbers)
             ELSE '[]'::jsonb
           END
         ) AS order_number),
        '[]'::jsonb
      )
    END;

    RETURN jsonb_build_object(
      'ok', TRUE,
      'invitation', jsonb_build_object(
        'orderId', COALESCE(v_invitation.order_group_id, v_group.id)::text,
        'orderGroupId', COALESCE(v_invitation.order_group_id, v_group.id)::text,
        'state', v_state,
        'token', p_token,
        'orderNumber', v_order_number,
        'customerName', v_customer_name,
        'customerPhone', v_customer_phone,
        'orderItems', v_order_items,
        'availableSlots', COALESCE(to_jsonb(v_invitation.available_slots), '[]'::jsonb),
        'deliveryDate', v_invitation.delivery_date,
        'deliveryTime', v_invitation.delivery_time,
        'orderStatus', NULL,
        'deliveryAgreementStatus', NULL
      )
    );
  END IF;

  SELECT id, order_number, status, delivery_agreement_status, customer
  INTO v_order
  FROM public.orders
  WHERE id = v_invitation.order_id;

  IF NOT found THEN
    RAISE EXCEPTION 'Order not found';
  END IF;

  v_state := CASE v_order.status
    WHEN 'Ожидает ответа клиента' THEN 'awaiting_choice'
    WHEN 'Ожидает согласования доставки' THEN 'opened'
    WHEN 'Напоминание отправлено' THEN 'reminder_sent'
    WHEN 'Переход отправлен' THEN 'reminder_sent'
    WHEN 'Передан логисту' THEN 'transferred_to_logistics'
    WHEN 'Платное хранение' THEN 'paid_storage'
    WHEN 'Доставлен' THEN 'delivered'
    WHEN 'Доставка согласована' THEN 'agreed'
    ELSE 'default'
  END;

  UPDATE public.delivery_invitations
  SET
    opened_at = CASE
      WHEN v_state IN ('awaiting_choice', 'opened', 'reminder_sent') AND opened_at IS NULL THEN v_now
      ELSE opened_at
    END,
    access_count = COALESCE(access_count, 0) + 1,
    last_accessed_at = v_now
  WHERE id = v_invitation.id
  RETURNING * INTO v_invitation;

  v_order_items := CASE
    WHEN jsonb_typeof(v_order.customer -> 'items') = 'array' THEN v_order.customer -> 'items'
    ELSE '[]'::jsonb
  END;

  RETURN jsonb_build_object(
    'ok', TRUE,
    'invitation', jsonb_build_object(
      'orderId', v_invitation.order_id::text,
      'state', v_state,
      'token', p_token,
      'orderNumber', COALESCE(NULLIF(v_order.order_number, ''), NULLIF(v_invitation.order_number, '')),
      'customerName', COALESCE(NULLIF(v_order.customer ->> 'name', ''), NULLIF(v_invitation.customer_name, '')),
      'customerPhone', COALESCE(NULLIF(v_order.customer ->> 'phone', ''), NULLIF(v_invitation.customer_phone, '')),
      'orderItems', v_order_items,
      'availableSlots', COALESCE(to_jsonb(v_invitation.available_slots), '[]'::jsonb),
      'deliveryDate', v_invitation.delivery_date,
      'deliveryTime', v_invitation.delivery_time,
      'orderStatus', v_order.status,
      'deliveryAgreementStatus', v_order.delivery_agreement_status
    )
  );
END;
$$;

REVOKE ALL ON FUNCTION public.get_delivery_invitation_by_token(text) FROM public;
GRANT EXECUTE ON FUNCTION public.get_delivery_invitation_by_token(text) TO anon, authenticated;
