-- Created 2026-08-12. Filename intentionally follows the existing
-- 20260813010000 migration; the identifier is an ordering key.
begin;

alter table public.agentic_rectification_tool_receipts
  add column if not exists executed_methods jsonb not null default '[]'::jsonb
  check (jsonb_typeof(executed_methods) = 'array');

drop function if exists public.insert_agentic_rectification_tool_receipt(
  uuid, uuid, uuid, text, text, text, text, text, text, text
);

create or replace function public.insert_agentic_rectification_tool_receipt(
  p_user_id uuid,
  p_case_id uuid,
  p_turn_id uuid,
  p_tool_name text,
  p_public_phase text,
  p_status text,
  p_input_fingerprint text,
  p_result_fingerprint text,
  p_engine_version text,
  p_safe_error_code text,
  p_executed_methods jsonb
)
returns jsonb
language plpgsql
security definer
set search_path = ''
as $$
declare
  v_receipt_id uuid;
  v_turn_count bigint;
begin
  if p_user_id is null or p_case_id is null or p_turn_id is null
    or p_executed_methods is null
    or jsonb_typeof(p_executed_methods) <> 'array'
    or exists (
      select 1
      from jsonb_array_elements_text(p_executed_methods) as method(value)
      where method.value not in (
        'd1-rashi', 'd2-hora', 'd4-chaturthamsha', 'd9-navamsa',
        'd10-dashamsa', 'd11-labhamsha', 'd24-chaturvimshamsha',
        'd30-trimshamsha', 'vimshottari-dasha', 'narayana-dasha',
        'gochara', 'ashtakavarga', 'shadbala', 'arudha-pada',
        'functional-benefic-malefic'
      )
    ) then
    raise exception 'agentic_rectification_invalid_input' using errcode = 'P0001';
  end if;
  if not exists (
    select 1 from public.agentic_rectification_cases
    where id = p_case_id and user_id = p_user_id
  ) then
    raise exception 'agentic_rectification_case_not_found' using errcode = 'P0001';
  end if;
  select count(*) into v_turn_count
  from public.agentic_rectification_turns
  where id = p_turn_id and case_id = p_case_id;
  if v_turn_count = 0 then
    raise exception 'agentic_rectification_turn_not_found' using errcode = 'P0001';
  end if;

  insert into public.agentic_rectification_tool_receipts (
    case_id, turn_id, tool_name, public_phase, status,
    input_fingerprint, result_fingerprint, engine_version, safe_error_code,
    executed_methods, completed_at
  ) values (
    p_case_id, p_turn_id, p_tool_name, p_public_phase, p_status,
    p_input_fingerprint, p_result_fingerprint, p_engine_version, p_safe_error_code,
    p_executed_methods,
    case when p_status = 'completed' then pg_catalog.now() else null end
  ) returning id into v_receipt_id;

  return jsonb_build_object('receipt_id', v_receipt_id);
end;
$$;

revoke all on function public.insert_agentic_rectification_tool_receipt(
  uuid, uuid, uuid, text, text, text, text, text, text, text, jsonb
) from public, anon, authenticated;
grant execute on function public.insert_agentic_rectification_tool_receipt(
  uuid, uuid, uuid, text, text, text, text, text, text, text, jsonb
) to service_role;

create or replace function public.get_agentic_rectification_turn_receipt(
  p_user_id uuid,
  p_case_id uuid,
  p_turn_id uuid
)
returns jsonb
language plpgsql
security definer
set search_path = ''
as $$
declare
  v_turn public.agentic_rectification_turns%rowtype;
  v_case public.agentic_rectification_cases%rowtype;
  v_phases jsonb;
  v_tools jsonb;
  v_methods jsonb;
  v_engine_version text;
begin
  if p_user_id is null or p_case_id is null or p_turn_id is null then
    raise exception 'agentic_rectification_invalid_input' using errcode = 'P0001';
  end if;
  select * into v_case
  from public.agentic_rectification_cases
  where id = p_case_id and user_id = p_user_id;
  if not found then
    raise exception 'agentic_rectification_case_not_found' using errcode = 'P0001';
  end if;
  select * into v_turn
  from public.agentic_rectification_turns
  where id = p_turn_id and case_id = p_case_id;
  if not found then
    raise exception 'agentic_rectification_turn_not_found' using errcode = 'P0001';
  end if;

  select coalesce(jsonb_agg(
    jsonb_build_object('phase', rp.phase, 'tool', rp.tool_name)
    order by rp.sequence
  ), '[]'::jsonb) into v_phases
  from public.agentic_rectification_run_phases rp
  where rp.turn_id = p_turn_id;

  select coalesce(jsonb_agg(tool_name order by tool_name), '[]'::jsonb) into v_tools
  from (
    select distinct tr.tool_name
    from public.agentic_rectification_tool_receipts tr
    where tr.turn_id = p_turn_id and tr.status = 'completed'
  ) tools;

  select coalesce(jsonb_agg(method order by method), '[]'::jsonb) into v_methods
  from (
    select distinct jsonb_array_elements_text(tr.executed_methods) as method
    from public.agentic_rectification_tool_receipts tr
    where tr.turn_id = p_turn_id and tr.status = 'completed'
  ) methods;

  select max(tr.engine_version) into v_engine_version
  from public.agentic_rectification_tool_receipts tr
  where tr.turn_id = p_turn_id and tr.engine_version is not null;

  return jsonb_build_object(
    'turn_id', v_turn.id,
    'status', v_turn.status,
    'skill_name', v_case.skill_name,
    'skill_version', v_case.skill_version,
    'engine_version', v_engine_version,
    'phases', v_phases,
    'tools', v_tools,
    'methods', v_methods,
    'started_at', v_turn.created_at,
    'completed_at', v_turn.completed_at
  );
end;
$$;

revoke all on function public.get_agentic_rectification_turn_receipt(uuid, uuid, uuid)
  from public, anon, authenticated;
grant execute on function public.get_agentic_rectification_turn_receipt(uuid, uuid, uuid)
  to service_role;

create temporary table rectification_birth_context_affected_cases on commit drop as
select c.id
from public.agentic_rectification_cases c
join public.profiles p on p.id = c.user_id
where c.status = any (public.agentic_rectification_resumable_statuses())
  and (
    nullif(btrim(c.baseline_birth_snapshot ->> 'birth_place_label'), '') is null
    or nullif(btrim(c.baseline_birth_snapshot ->> 'timezone_id'), '') is null
    or c.baseline_birth_snapshot ->> 'birth_place_label' is distinct from p.birth_place_label
    or c.baseline_birth_snapshot ->> 'timezone_id' is distinct from p.timezone_id
  );

update public.agentic_rectification_cases c
set baseline_birth_snapshot = c.baseline_birth_snapshot
      || jsonb_build_object(
        'birth_place_label', p.birth_place_label,
        'timezone_id', p.timezone_id
      )
from public.profiles p, rectification_birth_context_affected_cases affected
where c.id = affected.id
  and p.id = c.user_id
  and nullif(btrim(coalesce(p.birth_place_label, '')), '') is not null
  and nullif(btrim(coalesce(p.timezone_id, '')), '') is not null;

update public.agentic_rectification_cases c
set status = 'needs_rebaseline',
    updated_at = pg_catalog.now(),
    last_activity_at = pg_catalog.now()
from rectification_birth_context_affected_cases affected
where c.id = affected.id;

update public.agentic_rectification_results r
set invalidated_at = pg_catalog.now(),
    updated_at = pg_catalog.now()
from rectification_birth_context_affected_cases affected
where r.case_id = affected.id
  and r.invalidated_at is null;

create or replace function public.agentic_rectification_profiles_rebaseline_guard()
returns trigger
language plpgsql
security definer
set search_path = ''
as $$
begin
  if old.birth_date is distinct from new.birth_date
    or old.birth_place_label is distinct from new.birth_place_label
    or old.reported_birth_time is distinct from new.reported_birth_time
    or old.active_birth_time is distinct from new.active_birth_time
    or old.birth_time_source is distinct from new.birth_time_source
    or old.birth_time_period is distinct from new.birth_time_period
    or old.uncertainty_before_minutes is distinct from new.uncertainty_before_minutes
    or old.uncertainty_after_minutes is distinct from new.uncertainty_after_minutes
    or old.latitude is distinct from new.latitude
    or old.longitude is distinct from new.longitude
    or old.timezone_id is distinct from new.timezone_id
    or old.timezone_offset is distinct from new.timezone_offset then
    update public.agentic_rectification_cases
    set status = 'needs_rebaseline',
        updated_at = pg_catalog.now(),
        last_activity_at = pg_catalog.now()
    where user_id = new.id
      and status = any (public.agentic_rectification_resumable_statuses());
  end if;
  return new;
end;
$$;

revoke all on function public.agentic_rectification_profiles_rebaseline_guard()
  from public, anon, authenticated;
drop trigger if exists agentic_rectification_profiles_rebaseline_guard_trigger on public.profiles;
create trigger agentic_rectification_profiles_rebaseline_guard_trigger
after update of birth_date, birth_place_label, reported_birth_time, active_birth_time,
  birth_time_source, birth_time_period, uncertainty_before_minutes, uncertainty_after_minutes,
  latitude, longitude, timezone_id, timezone_offset
on public.profiles
for each row execute function public.agentic_rectification_profiles_rebaseline_guard();

create or replace function public.invalidate_agentic_rectification_results_on_profile_change()
returns trigger
language plpgsql
security definer
set search_path = ''
as $$
begin
  if old.birth_date is distinct from new.birth_date
    or old.birth_place_label is distinct from new.birth_place_label
    or old.reported_birth_time is distinct from new.reported_birth_time
    or old.birth_time_source is distinct from new.birth_time_source
    or old.birth_time_period is distinct from new.birth_time_period
    or old.uncertainty_before_minutes is distinct from new.uncertainty_before_minutes
    or old.uncertainty_after_minutes is distinct from new.uncertainty_after_minutes
    or old.latitude is distinct from new.latitude
    or old.longitude is distinct from new.longitude
    or old.timezone_id is distinct from new.timezone_id
    or old.timezone_offset is distinct from new.timezone_offset
    or (
      (old.active_birth_time is distinct from new.active_birth_time
        or old.birth_time_status is distinct from new.birth_time_status)
      and coalesce(new.birth_time_status, '') not in ('accepted', 'confirmed')
    ) then
    update public.agentic_rectification_results
    set invalidated_at = pg_catalog.now(),
        updated_at = pg_catalog.now()
    where user_id = new.id
      and invalidated_at is null;
  end if;
  return new;
end;
$$;

revoke all on function public.invalidate_agentic_rectification_results_on_profile_change()
  from public, anon, authenticated;
drop trigger if exists profiles_invalidate_agentic_rectification_results on public.profiles;
create trigger profiles_invalidate_agentic_rectification_results
after update of birth_date, birth_place_label, reported_birth_time, active_birth_time,
  birth_time_status, birth_time_source, birth_time_period, uncertainty_before_minutes,
  uncertainty_after_minutes, latitude, longitude, timezone_id, timezone_offset
on public.profiles
for each row execute function public.invalidate_agentic_rectification_results_on_profile_change();

commit;
