-- =====================================================================================
-- Trigger Function: handle_new_user
-- Version: v4
-- Purpose: auth.users 新用户创建后，优先读取 raw_user_meta_data.user_role 写入 ak_users.role。
--          解决 delivery / merchant 注册时被错误降级为默认 consumer 的问题。
-- Security: SECURITY DEFINER + 固定 search_path
-- Depends:
--   - public.ak_users(auth_id,email,username,role)
--   - public.user_roles(user_id,role)
-- =====================================================================================

CREATE OR REPLACE FUNCTION public.handle_new_user()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
DECLARE
  user_role TEXT;
  metadata_role TEXT;
  user_email TEXT := NEW.email;
  user_name TEXT;
  ak_user_id UUID;
  has_user_roles BOOLEAN := FALSE;
  has_delivery_staff BOOLEAN := FALSE;
BEGIN
  metadata_role := NULLIF(TRIM(COALESCE(NEW.raw_user_meta_data ->> 'user_role', '')), '');

  user_role := CASE
    WHEN metadata_role IN ('customer', 'merchant', 'delivery', 'service', 'admin') THEN metadata_role
    WHEN user_email ILIKE '%@admin.%' THEN 'admin'
    WHEN user_email ILIKE '%@teacher.%' OR user_email ILIKE '%@edu.%' THEN 'customer'
    ELSE 'customer'
  END;

  IF user_email IS NOT NULL AND POSITION('@' IN user_email) > 1 THEN
    user_name := SPLIT_PART(user_email, '@', 1);
  ELSE
    user_name := 'user_' || SUBSTRING(NEW.id::text, 1, 8);
  END IF;

  INSERT INTO public.ak_users (auth_id, email, username, role)
  VALUES (NEW.id, user_email, user_name, user_role)
  ON CONFLICT (auth_id)
  DO UPDATE SET
    email = COALESCE(EXCLUDED.email, public.ak_users.email),
    username = COALESCE(EXCLUDED.username, public.ak_users.username),
    role = COALESCE(NULLIF(public.ak_users.role, ''), EXCLUDED.role),
    updated_at = now()
  RETURNING id INTO ak_user_id;

  IF user_role = 'delivery' THEN
    SELECT EXISTS (
      SELECT 1
      FROM information_schema.tables
      WHERE table_schema = 'public'
        AND table_name = 'ml_delivery_staff'
    ) INTO has_delivery_staff;

    IF has_delivery_staff THEN
      INSERT INTO public.ml_delivery_staff (
        uid,
        nickname,
        phone,
        status,
        is_active
      )
      SELECT
        ak_user_id,
        user_name,
        '',
        1,
        TRUE
      WHERE NOT EXISTS (
        SELECT 1
        FROM public.ml_delivery_staff
        WHERE uid = ak_user_id
      );
    END IF;
  END IF;

  SELECT EXISTS (
    SELECT 1
    FROM information_schema.tables
    WHERE table_schema = 'public'
      AND table_name = 'user_roles'
  ) INTO has_user_roles;

  IF has_user_roles THEN
    BEGIN
      INSERT INTO public.user_roles (user_id, role, created_by)
      VALUES (NEW.id, user_role, NEW.id)
      ON CONFLICT DO NOTHING;
    EXCEPTION
      WHEN check_violation THEN
        RAISE NOTICE '[handle_new_user_v4] WARNING: Skipped user_roles insert due to check violation. user_id: %, role: %', NEW.id, user_role;
      WHEN not_null_violation THEN
        RAISE NOTICE '[handle_new_user_v4] WARNING: Failed to INSERT into user_roles due to NOT NULL violation. user_id: %, role: %', NEW.id, user_role;
      WHEN others THEN
        RAISE NOTICE '[handle_new_user_v4] WARNING: Skipped user_roles insert due to unexpected error. user_id: %, role: %, err: %', NEW.id, user_role, SQLERRM;
    END;
  END IF;

  UPDATE auth.users
  SET raw_user_meta_data = COALESCE(raw_user_meta_data, '{}'::jsonb) || jsonb_build_object('user_role', user_role)
  WHERE id = NEW.id;

  RETURN NEW;
END;
$$;