-- =====================================================
-- Missing Database Constraints
--
-- Adds CHECK constraints for data sanity, UNIQUE index
-- for email per account, and IBAN format validation.
--
-- Fixes existing invalid data before adding constraints.
-- =====================================================

-- Fix existing invalid data before adding constraints
UPDATE public.members SET date_of_birth = NULL
  WHERE date_of_birth IS NOT NULL AND date_of_birth > current_date;

UPDATE public.members SET exit_date = entry_date
  WHERE exit_date IS NOT NULL AND entry_date IS NOT NULL AND exit_date < entry_date;

UPDATE public.members SET entry_date = current_date
  WHERE entry_date IS NOT NULL AND entry_date > current_date;

-- Normalize IBANs in sepa_mandates to uppercase, strip spaces
UPDATE public.sepa_mandates
  SET iban = upper(regexp_replace(iban, '\s', '', 'g'))
  WHERE iban IS NOT NULL AND iban != '';

-- Date sanity constraints
ALTER TABLE public.members
  ADD CONSTRAINT chk_members_dob_not_future
  CHECK (date_of_birth IS NULL OR date_of_birth <= current_date);

ALTER TABLE public.members
  ADD CONSTRAINT chk_members_exit_after_entry
  CHECK (exit_date IS NULL OR entry_date IS NULL OR exit_date >= entry_date);

ALTER TABLE public.members
  ADD CONSTRAINT chk_members_entry_not_future
  CHECK (entry_date IS NULL OR entry_date <= current_date);

-- Email uniqueness per account (partial index — allows NULLs and empty strings)
CREATE UNIQUE INDEX IF NOT EXISTS uix_members_email_per_account
  ON public.members(account_id, lower(email))
  WHERE email IS NOT NULL AND email != '';

-- IBAN format on sepa_mandates (2-letter country + 2 check digits + 11-30 alphanumeric)
ALTER TABLE public.sepa_mandates
  ADD CONSTRAINT chk_sepa_iban_format
  CHECK (iban ~ '^[A-Z]{2}[0-9]{2}[A-Z0-9]{11,30}$');

-- Mandate reference must not be empty
ALTER TABLE public.sepa_mandates
  ADD CONSTRAINT chk_sepa_mandate_reference_not_empty
  CHECK (mandate_reference IS NOT NULL AND mandate_reference != '');

-- Member roles: from_date should not be after until_date
ALTER TABLE public.member_roles
  ADD CONSTRAINT chk_member_roles_date_range
  CHECK (until_date IS NULL OR from_date IS NULL OR until_date >= from_date);

-- Dues categories: amount must be non-negative
ALTER TABLE public.dues_categories
  ADD CONSTRAINT chk_dues_amount_non_negative
  CHECK (amount >= 0);
