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;
