-- =====================================================
-- SEPA Data Deduplication (Phase 1)
--
-- Problem: members table has inline SEPA fields (iban, bic,
-- account_holder, sepa_mandate_id, sepa_mandate_date,
-- sepa_mandate_status, sepa_mandate_sequence, sepa_bank_name)
-- AND a separate sepa_mandates table. sepa_mandate_id is text,
-- not a FK to sepa_mandates(id) which is uuid. Data diverges.
--
-- Fix: Add proper primary_mandate_id FK, migrate inline data
-- to sepa_mandates rows, rewrite RPCs to read from sepa_mandates.
-- Inline columns are kept read-only for backward compat (phase 2 drops them).
-- =====================================================

-- Step 1: Add proper FK column pointing to the primary mandate
ALTER TABLE public.members
  ADD COLUMN IF NOT EXISTS primary_mandate_id uuid
  REFERENCES public.sepa_mandates(id) ON DELETE SET NULL;

CREATE INDEX IF NOT EXISTS ix_members_primary_mandate
  ON public.members(primary_mandate_id)
  WHERE primary_mandate_id IS NOT NULL;

-- Step 2: For members with inline SEPA data but no sepa_mandates row, create one
DO $$
DECLARE
  r record;
  v_mandate_id uuid;
BEGIN
  FOR r IN
    SELECT m.id AS member_id, m.account_id,
           m.iban, m.bic, m.account_holder,
           m.first_name, m.last_name,
           m.sepa_mandate_id, m.sepa_mandate_date,
           m.sepa_mandate_status, m.sepa_mandate_reference,
           m.sepa_mandate_sequence, m.sepa_bank_name
    FROM public.members m
    WHERE m.iban IS NOT NULL AND m.iban != ''
      AND NOT EXISTS (
        SELECT 1 FROM public.sepa_mandates sm WHERE sm.member_id = m.id
      )
  LOOP
    INSERT INTO public.sepa_mandates (
      member_id, account_id, mandate_reference, iban, bic,
      account_holder, mandate_date, status, sequence, is_primary, notes
    ) VALUES (
      r.member_id,
      r.account_id,
      COALESCE(NULLIF(r.sepa_mandate_reference, ''), NULLIF(r.sepa_mandate_id, ''), 'MIGRATED-' || r.member_id::text),
      r.iban,
      r.bic,
      COALESCE(NULLIF(r.account_holder, ''), NULLIF(TRIM(COALESCE(r.first_name, '') || ' ' || COALESCE(r.last_name, '')), ''), 'Unbekannt'),
      COALESCE(r.sepa_mandate_date, current_date),
      COALESCE(r.sepa_mandate_status, 'pending'::public.sepa_mandate_status),
      COALESCE(NULLIF(r.sepa_mandate_sequence, ''), 'RCUR'),
      true,
      CASE WHEN r.sepa_bank_name IS NOT NULL AND r.sepa_bank_name != ''
        THEN 'Bank: ' || r.sepa_bank_name
        ELSE NULL
      END
    )
    RETURNING id INTO v_mandate_id;

    UPDATE public.members SET primary_mandate_id = v_mandate_id WHERE id = r.member_id;
  END LOOP;
END $$;

-- Step 3: For members that already have sepa_mandates rows, link the primary one
UPDATE public.members m
SET primary_mandate_id = sm.id
FROM public.sepa_mandates sm
WHERE sm.member_id = m.id
  AND sm.is_primary = true
  AND m.primary_mandate_id IS NULL;

-- If no mandate marked as primary, pick the most recent active one
UPDATE public.members m
SET primary_mandate_id = (
  SELECT sm.id FROM public.sepa_mandates sm
  WHERE sm.member_id = m.id
  ORDER BY
    CASE WHEN sm.status = 'active' THEN 0 ELSE 1 END,
    sm.created_at DESC
  LIMIT 1
)
WHERE m.primary_mandate_id IS NULL
  AND EXISTS (SELECT 1 FROM public.sepa_mandates sm WHERE sm.member_id = m.id);

-- Step 4: Rewrite list_hierarchy_sepa_eligible_members to read from sepa_mandates
CREATE OR REPLACE FUNCTION public.list_hierarchy_sepa_eligible_members(
  root_account_id uuid,
  p_account_filter uuid DEFAULT NULL
)
RETURNS TABLE (
  member_id uuid,
  account_id uuid,
  account_name varchar,
  first_name text,
  last_name text,
  iban text,
  bic text,
  account_holder text,
  mandate_id text,
  mandate_date date,
  dues_amount numeric
)
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = ''
AS $$
BEGIN
  IF NOT public.has_role_on_account(root_account_id) THEN
    RETURN;
  END IF;

  RETURN QUERY
  SELECT
    m.id AS member_id,
    m.account_id,
    a.name AS account_name,
    m.first_name,
    m.last_name,
    sm.iban,
    sm.bic,
    sm.account_holder,
    sm.mandate_reference AS mandate_id,
    sm.mandate_date,
    COALESCE(dc.amount, 0) AS dues_amount
  FROM public.members m
  JOIN public.accounts a ON a.id = m.account_id
  JOIN public.sepa_mandates sm ON sm.id = m.primary_mandate_id
  LEFT JOIN public.dues_categories dc ON dc.id = m.dues_category_id
  WHERE m.account_id IN (SELECT d FROM public.get_account_descendants(root_account_id) d)
    AND m.status = 'active'
    AND sm.iban IS NOT NULL
    AND sm.status = 'active'
    AND (p_account_filter IS NULL OR m.account_id = p_account_filter)
  ORDER BY a.name, m.last_name, m.first_name;
END;
$$;

-- Step 5: Add partial index for fast SEPA-eligible lookups
CREATE INDEX IF NOT EXISTS ix_sepa_mandates_active_primary
  ON public.sepa_mandates(member_id)
  WHERE status = 'active' AND is_primary = true;

-- Note: Inline SEPA columns (iban, bic, account_holder, sepa_mandate_id,
-- sepa_mandate_date, sepa_mandate_status, sepa_mandate_sequence, sepa_bank_name)
-- are kept for read-only backward compatibility. Phase 2 migration will drop them
-- after all code paths are migrated to use sepa_mandates via primary_mandate_id.
