
-- Per-bill, per-board-member secure approval tokens for email approve/deny.
-- Updated to use approver_name (post bill_approvals.vendor_name rename) and
-- populate approved_by/created_by from the board member's user_id.
CREATE TABLE IF NOT EXISTS public.bill_approval_email_tokens (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  bill_id uuid NOT NULL REFERENCES public.bills(id) ON DELETE CASCADE,
  board_member_id uuid NOT NULL REFERENCES public.board_members(id) ON DELETE CASCADE,
  token uuid NOT NULL DEFAULT gen_random_uuid() UNIQUE,
  email text NOT NULL,
  member_name text,
  sent_at timestamptz,
  acted_at timestamptz,
  action text CHECK (action IN ('approved','denied')),
  notes text,
  created_at timestamptz NOT NULL DEFAULT now(),
  UNIQUE (bill_id, board_member_id)
);
CREATE INDEX IF NOT EXISTS idx_baet_token ON public.bill_approval_email_tokens(token);
CREATE INDEX IF NOT EXISTS idx_baet_bill ON public.bill_approval_email_tokens(bill_id);

ALTER TABLE public.bill_approval_email_tokens ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS "Staff manage bill approval tokens" ON public.bill_approval_email_tokens;
CREATE POLICY "Staff manage bill approval tokens" ON public.bill_approval_email_tokens
  TO authenticated
  USING (has_role(auth.uid(),'admin') OR has_role(auth.uid(),'manager'))
  WITH CHECK (has_role(auth.uid(),'admin') OR has_role(auth.uid(),'manager'));

-- Lookup RPC for the public page (anonymous-friendly, security definer).
-- The "vendor_name" returned here is the bill's vendor (from public.vendors),
-- not the approver.
CREATE OR REPLACE FUNCTION public.lookup_bill_approval_by_token(p_token uuid)
RETURNS TABLE (
  bill_id uuid,
  member_name text,
  member_email text,
  acted_at timestamptz,
  action text,
  vendor_name text,
  invoice_number text,
  bill_date date,
  due_date date,
  amount numeric,
  description text,
  attachment_url text,
  bill_status text,
  association_name text
)
LANGUAGE sql STABLE SECURITY DEFINER SET search_path = public
AS $$
  SELECT t.bill_id, t.member_name, t.email AS member_email, t.acted_at, t.action,
         v.name AS vendor_name, b.invoice_number, b.bill_date, b.due_date, b.amount,
         b.description, b.attachment_url, b.status AS bill_status, a.name AS association_name
  FROM bill_approval_email_tokens t
  JOIN bills b ON b.id = t.bill_id
  LEFT JOIN vendors v ON v.id = b.vendor_id
  LEFT JOIN associations a ON a.id = b.association_id
  WHERE t.token = p_token;
$$;
GRANT EXECUTE ON FUNCTION public.lookup_bill_approval_by_token(uuid) TO anon, authenticated;

-- Record action via token. Anonymous callers identify via the secret token;
-- the linked board_member.user_id (if any) is the audit identity we record.
CREATE OR REPLACE FUNCTION public.record_bill_approval_by_token(
  p_token uuid,
  p_action text,
  p_notes text DEFAULT NULL
)
RETURNS jsonb
LANGUAGE plpgsql SECURITY DEFINER SET search_path = public
AS $$
DECLARE
  tok        bill_approval_email_tokens%ROWTYPE;
  bill       bills%ROWTYPE;
  v_user_id  uuid;
BEGIN
  IF p_action NOT IN ('approved','denied') THEN
    RETURN jsonb_build_object('ok', false, 'error', 'Invalid action');
  END IF;

  SELECT * INTO tok FROM bill_approval_email_tokens WHERE token = p_token;
  IF NOT FOUND THEN
    RETURN jsonb_build_object('ok', false, 'error', 'Invalid token');
  END IF;
  IF tok.acted_at IS NOT NULL THEN
    RETURN jsonb_build_object(
      'ok', false, 'already_voted', true,
      'error', 'You have already responded', 'action', tok.action
    );
  END IF;

  SELECT * INTO bill FROM bills WHERE id = tok.bill_id;
  IF NOT FOUND THEN
    RETURN jsonb_build_object('ok', false, 'error', 'Bill not found');
  END IF;

  SELECT user_id INTO v_user_id FROM board_members WHERE id = tok.board_member_id;

  INSERT INTO bill_approvals (
    bill_id, association_id, approver_name, amount,
    status, notes, approved_date, approved_by, created_by
  ) VALUES (
    tok.bill_id, bill.association_id, COALESCE(tok.member_name, 'Board Member'), bill.amount,
    p_action, p_notes, CURRENT_DATE, v_user_id, v_user_id
  );

  -- public.bills.status is derived by the recompute_bill_status_from_approvals
  -- trigger from the votes — don't force-update here.

  UPDATE bill_approval_email_tokens
     SET acted_at = now(), action = p_action, notes = p_notes
   WHERE token = p_token;

  RETURN jsonb_build_object('ok', true, 'action', p_action);
END;
$$;
GRANT EXECUTE ON FUNCTION public.record_bill_approval_by_token(uuid, text, text) TO anon, authenticated;
