begin; create or replace function public.admin_reset_customer_account( p_actor_user_id uuid, p_target_user_id uuid, p_reason text, p_request_id text ) returns table ( user_id uuid, email text, credits integer, chat_sessions_deleted integer, chart_profiles_deleted integer, synastry_reports_deleted integer ) language plpgsql security definer set search_path = '' as $$ declare v_actor_email text; v_target_email text; v_profile_email text; v_credits integer; v_identity_accounts bigint; v_identity_sessions bigint; v_admin_user_roles bigint; v_credit_transactions bigint; v_credit_cancellations bigint; v_consultation_requests bigint; v_rectification_billing bigint; v_action_receipts bigint; v_redeemed_codes bigint; v_admin_audit_logs bigint; v_chat_sessions_deleted integer; v_chart_profiles_deleted integer; v_synastry_reports_deleted integer; begin if not public.admin_has_permission(p_actor_user_id, 'admin.users.manage_roles') then raise exception 'admin_permission_denied' using errcode = '42501'; end if; if p_target_user_id is null then raise exception 'admin_customer_scope_invalid' using errcode = '22023'; end if; if char_length(btrim(coalesce(p_reason, ''))) not between 1 and 500 then raise exception 'admin_reason_required' using errcode = '22023'; end if; if char_length(btrim(coalesce(p_request_id, ''))) not between 1 and 200 then raise exception 'admin_request_id_invalid' using errcode = '22023'; end if; select lower(btrim(value.email)) into v_actor_email from identity.users value where value.id = p_actor_user_id; if v_actor_email is null then raise exception 'admin_user_not_found' using errcode = '22023'; end if; select identity_user.email, profile.email, profile.credits, (select count(*) from identity.accounts value where value.user_id = identity_user.id), (select count(*) from identity.sessions value where value.user_id = identity_user.id), (select count(*) from public.admin_user_roles value where value.admin_user_id = identity_user.id), (select count(*) from public.credit_transactions value where value.user_id = identity_user.id), (select count(*) from public.credit_request_cancellations value where value.user_id = identity_user.id), (select count(*) from public.consultation_requests value where value.user_id = identity_user.id), (select count(*) from public.birth_time_rectification_billing value where value.user_id = identity_user.id), (select count(*) from public.birth_time_rectification_action_receipts value where value.user_id = identity_user.id), (select count(*) from public.redemption_codes value where value.redeemed_by = identity_user.id), (select count(*) from audit.admin_audit_logs value where value.actor_user_id = identity_user.id) into v_target_email, v_profile_email, v_credits, v_identity_accounts, v_identity_sessions, v_admin_user_roles, v_credit_transactions, v_credit_cancellations, v_consultation_requests, v_rectification_billing, v_action_receipts, v_redeemed_codes, v_admin_audit_logs from identity.users identity_user join auth.users auth_user on auth_user.id = identity_user.id join public.profiles profile on profile.id = identity_user.id where identity_user.id = p_target_user_id and lower(btrim(auth_user.email)) = lower(btrim(identity_user.email)) for update of identity_user, auth_user, profile; if not found then raise exception 'admin_customer_not_found_or_identity_bridge_mismatch' using errcode = 'P0002'; end if; update public.profiles set name = null, birth_date = null, birth_time = null, country_code = null, province_code = null, city_code = null, district_code = null, onboarding_payload = null, onboarding_version = null, onboarding_generated_at = null, latitude = null, longitude = null, timezone_offset = null, reported_birth_time = null, active_birth_time = null, birth_time_source = null, birth_time_period = null, birth_time_clue = null, uncertainty_before_minutes = null, uncertainty_after_minutes = null, birth_time_status = null, rectification_confidence = null, rectification_case_id = null, birth_place_label = null, birth_place_type = null, birth_place_provider = null, birth_place_provider_id = null, timezone_id = null, timezone_source = null, updated_at = pg_catalog.now() where id = p_target_user_id; delete from public.chat_sessions value where value.user_id = p_target_user_id; get diagnostics v_chat_sessions_deleted = row_count; delete from public.chart_profiles value where value.user_id = p_target_user_id; get diagnostics v_chart_profiles_deleted = row_count; delete from public.synastry_reports value where value.user_id = p_target_user_id; get diagnostics v_synastry_reports_deleted = row_count; if exists ( select 1 from identity.users identity_user join auth.users auth_user on auth_user.id = identity_user.id join public.profiles profile on profile.id = identity_user.id where identity_user.id = p_target_user_id and ( identity_user.email is distinct from v_target_email or auth_user.email is distinct from v_target_email or profile.email is distinct from v_profile_email or profile.credits is distinct from v_credits or (select count(*) from identity.accounts value where value.user_id = identity_user.id) <> v_identity_accounts or (select count(*) from identity.sessions value where value.user_id = identity_user.id) <> v_identity_sessions or (select count(*) from public.admin_user_roles value where value.admin_user_id = identity_user.id) <> v_admin_user_roles or (select count(*) from public.credit_transactions value where value.user_id = identity_user.id) <> v_credit_transactions or (select count(*) from public.credit_request_cancellations value where value.user_id = identity_user.id) <> v_credit_cancellations or (select count(*) from public.consultation_requests value where value.user_id = identity_user.id) <> v_consultation_requests or (select count(*) from public.birth_time_rectification_billing value where value.user_id = identity_user.id) <> v_rectification_billing or (select count(*) from public.birth_time_rectification_action_receipts value where value.user_id = identity_user.id) <> v_action_receipts or (select count(*) from public.redemption_codes value where value.redeemed_by = identity_user.id) <> v_redeemed_codes or (select count(*) from audit.admin_audit_logs value where value.actor_user_id = identity_user.id) <> v_admin_audit_logs ) ) then raise exception 'admin_customer_preserved_state_changed' using errcode = 'P0001'; end if; if exists (select 1 from public.chat_sessions value where value.user_id = p_target_user_id) or exists (select 1 from public.chart_profiles value where value.user_id = p_target_user_id) or exists (select 1 from public.synastry_reports value where value.user_id = p_target_user_id) or exists ( select 1 from public.profiles profile where profile.id = p_target_user_id and ( profile.name is not null or profile.birth_date is not null or profile.birth_time is not null or profile.country_code is not null or profile.province_code is not null or profile.city_code is not null or profile.district_code is not null or profile.onboarding_payload is not null or profile.onboarding_version is not null or profile.onboarding_generated_at is not null or profile.latitude is not null or profile.longitude is not null or profile.timezone_offset is not null or profile.reported_birth_time is not null or profile.active_birth_time is not null or profile.birth_time_source is not null or profile.birth_time_period is not null or profile.birth_time_clue is not null or profile.uncertainty_before_minutes is not null or profile.uncertainty_after_minutes is not null or profile.birth_time_status is not null or profile.rectification_confidence is not null or profile.rectification_case_id is not null or profile.birth_place_label is not null or profile.birth_place_type is not null or profile.birth_place_provider is not null or profile.birth_place_provider_id is not null or profile.timezone_id is not null or profile.timezone_source is not null ) ) then raise exception 'admin_customer_reset_state_not_empty' using errcode = 'P0001'; end if; insert into audit.admin_audit_logs ( actor_user_id, actor_email, actor_role, action, target_type, target_id, after_value, request_id, permission_used, reason ) values ( p_actor_user_id, v_actor_email, 'admin', 'admin.customer.account.reset', 'customer', p_target_user_id, jsonb_build_object( 'email', lower(btrim(v_target_email)), 'creditsPreserved', v_credits, 'chatSessionsDeleted', v_chat_sessions_deleted, 'chartProfilesDeleted', v_chart_profiles_deleted, 'synastryReportsDeleted', v_synastry_reports_deleted ), btrim(p_request_id), 'admin.users.manage_roles', btrim(p_reason) ) on conflict do nothing; return query select p_target_user_id, lower(btrim(v_target_email)), v_credits, v_chat_sessions_deleted, v_chart_profiles_deleted, v_synastry_reports_deleted; end; $$; revoke all on function public.admin_reset_customer_account(uuid, uuid, text, text) from public, anon, authenticated, service_role; do $$ begin if exists (select 1 from pg_roles where rolname = 'admin_runtime') then grant execute on function public.admin_reset_customer_account(uuid, uuid, text, text) to admin_runtime; end if; end; $$; commit;