-- Create a paid bill for a vendor payment transaction that has no attached bill.
-- Such payments post Dr Accounts Payable / Cr Bank (the Banking flow assumes a
-- bill exists); with no bill, A/P is left negative and the expense is never
-- recognized. The auto-bill posts Dr Expense / Cr A/P, clearing the A/P and
-- booking the expense (net: Dr Expense / Cr Bank). Idempotent + safe to re-run.
--
-- NOTE: superseded for the Banking flow by 20260603200530 (vendor payments now
-- book the expense directly). This function is retained for reference/backfill.
create or replace function accounting.create_bill_for_payment_txn(_txn_id uuid)
returns uuid
language plpgsql
security definer
set search_path to 'public','accounting'
as $$
declare
  t accounting.transactions%rowtype;
  _exp uuid;
  _num text;
  _n int;
  _bill_id uuid;
begin
  select * into t from accounting.transactions where id = _txn_id;
  if not found then return null; end if;

  if t.type <> 'debit' or t.vendor_id is null or t.coa_account_id is not null
     or t.transfer_id is not null or t.deposit_id is not null then
    return null;
  end if;
  if coalesce(t.amount, 0) <= 0 then return null; end if;
  if exists (select 1 from accounting.bills b where b.source_payment_id = t.id) then
    return null;
  end if;

  select a.id into _exp
  from accounting.accounts a
  where a.company_id = t.company_id and a.name = t.category and a.type = 'expense'
  limit 1;
  if _exp is null then _exp := accounting.coa_default_expense(t.company_id); end if;

  select count(*) into _n from accounting.bills where company_id = t.company_id and auto_created;
  _num := 'AUTO-BILL-' || lpad((_n + 1)::text, 4, '0');

  insert into accounting.bills
    (company_id, vendor_id, number, issue_date, due_date,
     subtotal, tax, total, paid_amount, status, notes,
     auto_created, source_payment_id, source_payment_kind)
  values
    (t.company_id, t.vendor_id, _num, t.date, t.date,
     t.amount, 0, t.amount, t.amount, 'paid',
     'Auto-created from bank payment with no attached bill',
     true, t.id, 'transaction')
  returning id into _bill_id;

  insert into accounting.bill_items (bill_id, description, quantity, rate, amount, account_id)
  values (_bill_id, coalesce(nullif(t.category, ''), 'Auto-created payment line'),
          1, t.amount, t.amount, _exp);

  return _bill_id;
end;
$$;

-- Backfill existing unattached vendor payments + best-effort link a matching check.
do $$
declare r record; _bill uuid;
begin
  for r in
    select t.id, t.company_id, t.vendor_id, t.amount, t.date
    from accounting.transactions t
    where t.type = 'debit'
      and t.vendor_id is not null
      and t.coa_account_id is null
      and t.transfer_id is null and t.deposit_id is null
      and coalesce(t.description, '') not ilike 'Bill Payment%'
      and not exists (select 1 from accounting.bills b where b.source_payment_id = t.id)
    order by t.date, t.id
  loop
    _bill := accounting.create_bill_for_payment_txn(r.id);
    if _bill is not null then
      update accounting.checks c
      set auto_bill_id = _bill, updated_at = now()
      where c.id = (
        select c2.id from accounting.checks c2
        where c2.company_id = r.company_id
          and c2.payee_vendor_id = r.vendor_id
          and c2.amount = r.amount
          and c2.date = r.date
          and c2.source_bill_id is null
          and c2.auto_bill_id is null
        limit 1
      );
    end if;
  end loop;
end $$;
