-- Explicit owner-initiated fresh inquiries. Existing run RPCs retain their
-- cached-success behavior, and the original evidence stays intact until a
-- provider response has been validated. No account is approved by this rollout.
begin;

-- A configuration placeholder, not an executable document-verification adapter.
-- Do not replace an administrator's existing endpoint or saved credentials.
insert into marketplace_private.inquiry_services(service_key,label,scope,provider_name,base_url,adapter_status)
values('document_authenticity','کنترل اصالت مدارک','other','','','awaiting_docs')
on conflict(service_key) do nothing;

-- Only private, validated adapters can apply a fresh result. Historical attempts
-- and their customer_activity snapshots are never replaced or deleted.
create or replace function marketplace_private.customer_inquiry_refresh_result(p_inquiry uuid,p_service uuid,p_status text,p_reference text) returns void
language plpgsql security definer set search_path='' as $$
declare i marketplace_private.identity_inquiries;r marketplace_private.identity_requests;
begin
 if public.marketplace_role() is distinct from 'owner' then raise exception 'not_authorized' using errcode='42501';end if;
 select * into i from marketplace_private.identity_inquiries where id=p_inquiry;
 select * into r from marketplace_private.identity_requests where id=i.request_id for update;
 select * into i from marketplace_private.identity_inquiries where id=p_inquiry for update;
 if i.id is null or r.status not in('pending','documents_approved','verified') then raise exception 'inquiry_not_pending';end if;
 if not exists(select 1 from marketplace_private.inquiry_services where id=p_service and scope=i.kind and adapter_status='ready' and vault_secret_id is not null) then raise exception 'adapter_not_ready';end if;
 if p_status is null or p_status not in('passed','failed','error') or p_reference is null or length(p_reference) not between 1 and 200 then raise exception 'invalid_inquiry_result';end if;
 if not exists(select 1 from auth.users where id=r.user_id and phone=r.phone and phone_confirmed_at is not null) then raise exception 'phone_changed';end if;
 update marketplace_private.identity_inquiries set status=p_status,service_id=p_service,provider_reference=p_reference,checked_at=now() where id=i.id;
 if i.kind='bank_owner' and p_status='passed' and exists(select 1 from marketplace_private.identity_requests where id=r.id and status='verified') then
  update marketplace_private.bank_accounts set status='verified' where id=i.bank_id and user_id=r.user_id and iban=i.bank_iban;
 end if;
 -- Preserve existing final-decision rules: fresh evidence alone cannot grant a
 -- level. Losing required evidence recalculates an existing grant as before.
 perform marketplace_private.identity_finalize(r.id);
end$$;
revoke all on function marketplace_private.customer_inquiry_refresh_result(uuid,uuid,text,text) from public,anon,authenticated,service_role;

-- Clone the installed trusted adapters into private fresh-only entry points.
-- Bypass their success cache and apply the validated result above. Fresh reads
-- do not rewrite the request's cached birth date: the locked account birth date
-- is already the authoritative input and the attestation fingerprint evidence.
-- All identity, consent, provider/Vault, lock,
-- cooldown, daily-limit and response-validation guards remain verbatim.
-- Fail closed if an installed adapter no longer has the expected contract.
do $$
declare source_name text;target_name text;definition text;cache_guard text:=$marker$if i.status='passed' then return public.marketplace_identity_admin(r.id);end if;$marker$;
 birthday_cache text:=$marker$update marketplace_private.identity_requests set birth_date=birthday,version=version+1,updated_at=now() where id=r.id and birth_date is distinct from birthday;$marker$;
begin
 for source_name,target_name in values
  ('marketplace_bank_inquiry_run','customer_bank_inquiry_refresh'),
  ('marketplace_identity_inquiry_run','customer_identity_inquiry_refresh')
 loop
  if to_regprocedure('public.'||source_name||'(uuid,uuid)') is null then raise exception 'inquiry_refresh_adapter_contract_missing';end if;
  select pg_get_functiondef(to_regprocedure('public.'||source_name||'(uuid,uuid)')) into definition;
  if position(cache_guard in definition)=0
   or position('perform public.marketplace_identity_inquiry_result(i.id,s.id,outcome,' in definition)=0
   or position('insert into marketplace_private.inquiry_attempts' in definition)=0
   or position('inquiry_retry_later' in definition)=0 or position('inquiry_daily_limit' in definition)=0
   or position('public.marketplace_role()' in definition)=0 then raise exception 'inquiry_refresh_adapter_contract_missing';end if;
  definition:=replace(definition,'FUNCTION public.'||source_name||'(','FUNCTION marketplace_private.'||target_name||'(');
  definition:=replace(definition,cache_guard,'-- Fresh execution was explicitly requested by the owner.');
  definition:=replace(definition,'-- A completed match for this exact bank and identity is not billed again.','-- Previous evidence is retained until the fresh provider result arrives.');
  definition:=replace(definition,'perform public.marketplace_identity_inquiry_result(i.id,s.id,outcome,','perform marketplace_private.customer_inquiry_refresh_result(i.id,s.id,outcome,');
  definition:=replace(definition,'return public.marketplace_bank_inquiry_run(p_inquiry,p_service);','return marketplace_private.customer_bank_inquiry_refresh(p_inquiry,p_service);');
  if source_name='marketplace_identity_inquiry_run' then
   if position(birthday_cache in definition)=0 then raise exception 'inquiry_refresh_adapter_contract_missing';end if;
   definition:=replace(definition,birthday_cache,'-- Keep attested request evidence unchanged; use the locked account birthday above.');
  end if;
  if position('FUNCTION marketplace_private.'||target_name||'(' in definition)=0 then raise exception 'inquiry_refresh_adapter_contract_missing';end if;
  execute definition;
  execute 'revoke all on function marketplace_private.'||target_name||'(uuid,uuid) from public,anon,authenticated,service_role';
 end loop;
end$$;

create or replace function public.marketplace_admin_customer_inquiry_refresh(p_user uuid,p_inquiry uuid,p_service uuid,p_version integer) returns jsonb
language plpgsql security definer set search_path='' as $$
declare r marketplace_private.identity_requests;i marketplace_private.identity_inquiries;s marketplace_private.inquiry_services;
begin
 if public.marketplace_role() is distinct from 'owner' then raise exception 'not_authorized' using errcode='42501';end if;
 if p_user is null or not exists(select 1 from marketplace_private.customer_profiles where user_id=p_user) then raise exception 'customer_not_found';end if;
 perform pg_advisory_xact_lock(hashtextextended('identity:'||p_user::text,0));
 select * into r from marketplace_private.identity_requests where user_id=p_user order by created_at desc,id desc limit 1 for update;
 if r.id is null then raise exception 'inquiry_not_pending';end if;
 if r.version is distinct from p_version then raise exception 'identity_conflict';end if;
 select * into i from marketplace_private.identity_inquiries where id=p_inquiry and request_id=r.id;
 if i.id is null then raise exception 'inquiry_customer_mismatch';end if;
 select * into s from marketplace_private.inquiry_services where id=p_service for share;
 if s.id is null or s.scope is distinct from i.kind or not marketplace_private.customer_inquiry_adapter_supported(s.scope,s.provider_name,s.base_url) then raise exception 'adapter_not_ready';end if;
 if i.kind='bank_owner' then
  perform 1 from marketplace_private.bank_accounts b where b.id=i.bank_id and b.user_id=p_user and b.iban=i.bank_iban and b.status<>'rejected' for update;
  if not found then raise exception 'bank_changed';end if;
  perform marketplace_private.customer_bank_inquiry_refresh(i.id,s.id);
 elsif i.kind in('identity','mobile_owner') then perform marketplace_private.customer_identity_inquiry_refresh(i.id,s.id);
 else raise exception 'adapter_not_ready';end if;
 return public.marketplace_admin_customer_inquiries(p_user);
end$$;
revoke all on function public.marketplace_admin_customer_inquiry_refresh(uuid,uuid,uuid,integer) from public,anon,service_role;
grant execute on function public.marketplace_admin_customer_inquiry_refresh(uuid,uuid,uuid,integer) to authenticated;

-- The existing owner-only overview remains read-only. Clients must use this
-- capability to distinguish a deployment supporting a real fresh inquiry.
do $$
declare definition text;candidate text;matched boolean:=false;marker text:=$marker$'user_id',p_user,'server_time',now(),$marker$;
begin
 foreach candidate in array array['public.marketplace_admin_customer_inquiries(uuid)','marketplace_private.temporary_base_marketplace_admin_customer_inquiries(uuid)'] loop
  if to_regprocedure(candidate) is null then continue;end if;
  select pg_get_functiondef(to_regprocedure(candidate)) into definition;
  if position($marker$'supports_manual_refresh',true$marker$ in definition)>0 then matched:=true;
  elsif position(marker in definition)>0 then
   definition:=replace(definition,marker,marker||$marker$'supports_manual_refresh',true,$marker$);
   execute definition;matched:=true;
  end if;
 end loop;
 if not matched then raise exception 'inquiry_refresh_overview_contract_missing';end if;
end$$;
notify pgrst,'reload schema';
commit;
