-- Migration: Enhanced member search and quick stats
-- Adds: full-text search index, quick stats RPC, next member number function

-- Full-text search index (German) for faster member search
CREATE INDEX IF NOT EXISTS ix_members_fulltext ON public.members
  USING gin(
    to_tsvector(
      'german',
      coalesce(first_name, '') || ' ' ||
      coalesce(last_name, '') || ' ' ||
      coalesce(email, '') || ' ' ||
      coalesce(member_number, '') || ' ' ||
      coalesce(city, '')
    )
  );

-- Trigram index on names for fuzzy / ILIKE search
CREATE INDEX IF NOT EXISTS ix_members_name_trgm
  ON public.members
  USING gin ((lower(first_name || ' ' || last_name)) gin_trgm_ops);

-- Quick stats RPC — returns a single row with KPI counts
-- Includes has_role_on_account guard to prevent cross-tenant data leaks
CREATE OR REPLACE FUNCTION public.get_member_quick_stats(p_account_id uuid)
RETURNS TABLE(
  total bigint,
  active bigint,
  inactive bigint,
  pending bigint,
  resigned bigint,
  new_this_year bigint,
  pending_applications bigint
)
LANGUAGE plpgsql STABLE SECURITY DEFINER
SET search_path = ''
AS $$
BEGIN
  -- Verify caller has access to this account
  IF NOT public.has_role_on_account(p_account_id) THEN
    RAISE EXCEPTION 'Access denied to account %', p_account_id;
  END IF;

  RETURN QUERY
  SELECT
    count(*)::bigint AS total,
    count(*) FILTER (WHERE m.status = 'active')::bigint AS active,
    count(*) FILTER (WHERE m.status = 'inactive')::bigint AS inactive,
    count(*) FILTER (WHERE m.status = 'pending')::bigint AS pending,
    count(*) FILTER (WHERE m.status = 'resigned')::bigint AS resigned,
    count(*) FILTER (WHERE m.status = 'active'
      AND m.entry_date >= date_trunc('year', current_date)::date)::bigint AS new_this_year,
    (
      SELECT count(*)
      FROM public.membership_applications a
      WHERE a.account_id = p_account_id
        AND a.status = 'submitted'
    )::bigint AS pending_applications
  FROM public.members m
  WHERE m.account_id = p_account_id;
END;
$$;

GRANT EXECUTE ON FUNCTION public.get_member_quick_stats(uuid) TO authenticated;

-- Next member number: returns max(member_number) + 1 as text
-- Includes has_role_on_account guard
CREATE OR REPLACE FUNCTION public.get_next_member_number(p_account_id uuid)
RETURNS text
LANGUAGE plpgsql STABLE SECURITY DEFINER
SET search_path = ''
AS $$
DECLARE
  v_result text;
BEGIN
  -- Verify caller has access to this account
  IF NOT public.has_role_on_account(p_account_id) THEN
    RAISE EXCEPTION 'Access denied to account %', p_account_id;
  END IF;

  SELECT LPAD(
    (COALESCE(
      MAX(
        CASE
          WHEN member_number ~ '^\d+$' THEN member_number::integer
          ELSE 0
        END
      ),
      0
    ) + 1)::text,
    4,
    '0'
  ) INTO v_result
  FROM public.members
  WHERE account_id = p_account_id;

  RETURN v_result;
END;
$$;

GRANT EXECUTE ON FUNCTION public.get_next_member_number(uuid) TO authenticated;
