-- pgz_sport.clanovi — schema lockdown DDL (Subagent D)
-- Author: dradulic@outlook.com / damir@rinet.one
-- Date: 2026-05-05
-- Description: Final, applied DDL. Pre-flight all-clean blocks below were
--              committed; SKIPPED candidates (length>=2 CHECK, klub+name+dob
--              UNIQUE) are documented in D_violations.md and intentionally
--              omitted here.
--
-- Row count at apply time: 3240 (live), 3243 (backup_20260505_0836).
-- Rollback hints: each block is independent and reversible via
--   ALTER TABLE pgz_sport.clanovi DROP CONSTRAINT ...;
--   DROP INDEX pgz_sport.clanovi_hns_uniq;
--   DROP TRIGGER clanovi_normalize_trigger ON pgz_sport.clanovi;
--   DROP FUNCTION pgz_sport.clanovi_normalize_fn();

-- ===========================================================================
-- C1: CHECK no internal CamelCase boundary (lower->upper letter pair)
-- Pre-flight violators: 0
-- ===========================================================================
BEGIN;
ALTER TABLE pgz_sport.clanovi
  ADD CONSTRAINT clanovi_no_camelcase_chk
  CHECK (
    ime !~ '[a-zćčšđžáàâäéèêëíìîïóòôöúùûüñçý][A-ZĆČŠĐŽÁÀÂÄÉÈÊËÍÌÎÏÓÒÔÖÚÙÛÜÑÇÝ]'
    AND prezime !~ '[a-zćčšđžáàâäéèêëíìîïóòôöúùûüñçý][A-ZĆČŠĐŽÁÀÂÄÉÈÊËÍÌÎÏÓÒÔÖÚÙÛÜÑÇÝ]'
  );
COMMIT;

-- ===========================================================================
-- C2: CHECK ime/prezime are trimmed
-- Pre-flight violators: 0
-- ===========================================================================
BEGIN;
ALTER TABLE pgz_sport.clanovi
  ADD CONSTRAINT clanovi_trimmed_chk
  CHECK (ime = trim(ime) AND prezime = trim(prezime));
COMMIT;

-- ===========================================================================
-- C4: spol values constraint
-- NOT applied as new constraint — existing clanovi_spol_check already enforces
-- spol IN ('M','Ž',NULL). Documented for completeness.
--   CHECK (spol IS NULL OR spol IN ('M','Ž'))
-- ===========================================================================

-- ===========================================================================
-- C5: UNIQUE partial index on hns_igrac_id (non-null, non-empty)
-- Pre-flight duplicate groups: 0
-- ===========================================================================
BEGIN;
CREATE UNIQUE INDEX IF NOT EXISTS clanovi_hns_uniq
  ON pgz_sport.clanovi (hns_igrac_id)
  WHERE hns_igrac_id IS NOT NULL AND hns_igrac_id != '';
COMMIT;

-- ===========================================================================
-- C7: BEFORE INSERT/UPDATE normalize trigger
-- Trims ime/prezime, rejects CamelCase, enforces length>=2 only when names
-- change (so the existing 22 short-name historical rows can still be UPDATEd
-- on other fields without rejection).
-- ===========================================================================
BEGIN;

CREATE OR REPLACE FUNCTION pgz_sport.clanovi_normalize_fn()
RETURNS trigger
LANGUAGE plpgsql
AS $fn$
DECLARE
  v_changed_name boolean;
BEGIN
  IF NEW.ime IS NOT NULL THEN
    NEW.ime := trim(NEW.ime);
  END IF;
  IF NEW.prezime IS NOT NULL THEN
    NEW.prezime := trim(NEW.prezime);
  END IF;

  IF TG_OP = 'INSERT' THEN
    v_changed_name := true;
  ELSE
    v_changed_name := (NEW.ime IS DISTINCT FROM OLD.ime)
                   OR (NEW.prezime IS DISTINCT FROM OLD.prezime);
  END IF;

  IF v_changed_name THEN
    IF NEW.ime ~ '[a-zćčšđžáàâäéèêëíìîïóòôöúùûüñçý][A-ZĆČŠĐŽÁÀÂÄÉÈÊËÍÌÎÏÓÒÔÖÚÙÛÜÑÇÝ]' THEN
      RAISE EXCEPTION 'CamelCase rejected in ime: %', NEW.ime
        USING ERRCODE = 'check_violation';
    END IF;
    IF NEW.prezime ~ '[a-zćčšđžáàâäéèêëíìîïóòôöúùûüñçý][A-ZĆČŠĐŽÁÀÂÄÉÈÊËÍÌÎÏÓÒÔÖÚÙÛÜÑÇÝ]' THEN
      RAISE EXCEPTION 'CamelCase rejected in prezime: %', NEW.prezime
        USING ERRCODE = 'check_violation';
    END IF;
    IF length(coalesce(NEW.ime, '')) < 2 THEN
      RAISE EXCEPTION 'ime too short (<2 chars): %', NEW.ime
        USING ERRCODE = 'check_violation';
    END IF;
    IF length(coalesce(NEW.prezime, '')) < 2 THEN
      RAISE EXCEPTION 'prezime too short (<2 chars): %', NEW.prezime
        USING ERRCODE = 'check_violation';
    END IF;
  END IF;

  RETURN NEW;
END;
$fn$;

DROP TRIGGER IF EXISTS clanovi_normalize_trigger ON pgz_sport.clanovi;

CREATE TRIGGER clanovi_normalize_trigger
  BEFORE INSERT OR UPDATE ON pgz_sport.clanovi
  FOR EACH ROW EXECUTE FUNCTION pgz_sport.clanovi_normalize_fn();

COMMIT;

-- END
