-- Add ON DELETE CASCADE foreign keys to the powerdns child tables.
--
-- BUG SURFACED: during a manual `DELETE FROM powerdns.domains WHERE ...` wipe
-- on whp02 (alsacorp), 163 rows in powerdns.records were left orphaned. The
-- PowerDNS-provided gmysql schema (the canonical one we download from upstream
-- in scripts/setup-powerdns-enhanced.sh) ships WITHOUT foreign keys on
-- records/comments/domainmetadata/cryptokeys, so dropping a row in `domains`
-- silently leaks every dependent child row. PowerDNS still serves those
-- orphan records until something cleans them up.
--
-- WHP's own deleteZoneForDomain() path goes through the PowerDNS HTTP API,
-- which cleans up dependent rows server-side, so customer-driven flows have
-- masked the problem so far. The first time it bit us was the direct-DB
-- alsacorp wipe; the next time will be any future direct-DB manipulation or
-- any bypass of the API (e.g. a CLI cleanup, an ops script, a panicked
-- support engineer at 2am). Adding CASCADE FKs is the only defense that
-- protects all of those paths.
--
-- This migration runs against the `powerdns` schema, NOT `whp`. It is
-- idempotent: if the FKs already exist (or anything else has named them
-- the same), it skips the add. It also cleans up pre-existing orphans
-- BEFORE adding the FK — InnoDB refuses to add a FK when orphans exist.
--
-- Tables touched:
--   powerdns.records         (orphan records — the bug Josh saw)
--   powerdns.comments        (orphan comments)
--   powerdns.domainmetadata  (orphan SOA-EDIT-API and similar)
--   powerdns.cryptokeys      (orphan DNSSEC keys)
--
-- If the `powerdns` schema doesn't exist on a given server (rare, but
-- possible on a pre-pdns or non-pdns build), the procedure no-ops the
-- whole migration instead of failing the update.

-- Procedural DDL requires USE — schema-qualifying inside the procedure
-- body isn't enough for CREATE/DROP PROCEDURE itself.
USE powerdns;

DROP PROCEDURE IF EXISTS whp_pdns_add_cascade_fks;

DELIMITER //

CREATE PROCEDURE whp_pdns_add_cascade_fks()
BEGIN
    DECLARE schema_exists INT DEFAULT 0;
    DECLARE fk_count INT DEFAULT 0;
    DECLARE orphans_records INT DEFAULT 0;
    DECLARE orphans_comments INT DEFAULT 0;
    DECLARE orphans_metadata INT DEFAULT 0;
    DECLARE orphans_cryptokeys INT DEFAULT 0;

    SELECT COUNT(*) INTO schema_exists
      FROM information_schema.SCHEMATA
      WHERE SCHEMA_NAME = 'powerdns';

    IF schema_exists = 0 THEN
        -- Nothing to do on servers without powerdns.
        SELECT 'powerdns schema not present, skipping cascade FK install' AS info;
    ELSE
        -- 1. Records ----------------------------------------------------
        SELECT COUNT(*) INTO orphans_records
          FROM powerdns.records r
          LEFT JOIN powerdns.domains d ON r.domain_id = d.id
          WHERE d.id IS NULL;
        IF orphans_records > 0 THEN
            DELETE r FROM powerdns.records r
              LEFT JOIN powerdns.domains d ON r.domain_id = d.id
              WHERE d.id IS NULL;
            SELECT CONCAT('Cleaned ', orphans_records, ' orphan rows from powerdns.records') AS info;
        END IF;

        SELECT COUNT(*) INTO fk_count
          FROM information_schema.TABLE_CONSTRAINTS
          WHERE CONSTRAINT_SCHEMA = 'powerdns'
            AND TABLE_NAME = 'records'
            AND CONSTRAINT_TYPE = 'FOREIGN KEY';
        IF fk_count = 0 THEN
            ALTER TABLE powerdns.records
              ADD CONSTRAINT fk_records_domain
                FOREIGN KEY (domain_id) REFERENCES powerdns.domains(id)
                ON DELETE CASCADE ON UPDATE CASCADE;
        END IF;

        -- 2. Comments ---------------------------------------------------
        SELECT COUNT(*) INTO orphans_comments
          FROM powerdns.comments c
          LEFT JOIN powerdns.domains d ON c.domain_id = d.id
          WHERE d.id IS NULL;
        IF orphans_comments > 0 THEN
            DELETE c FROM powerdns.comments c
              LEFT JOIN powerdns.domains d ON c.domain_id = d.id
              WHERE d.id IS NULL;
            SELECT CONCAT('Cleaned ', orphans_comments, ' orphan rows from powerdns.comments') AS info;
        END IF;

        SELECT COUNT(*) INTO fk_count
          FROM information_schema.TABLE_CONSTRAINTS
          WHERE CONSTRAINT_SCHEMA = 'powerdns'
            AND TABLE_NAME = 'comments'
            AND CONSTRAINT_TYPE = 'FOREIGN KEY';
        IF fk_count = 0 THEN
            ALTER TABLE powerdns.comments
              ADD CONSTRAINT fk_comments_domain
                FOREIGN KEY (domain_id) REFERENCES powerdns.domains(id)
                ON DELETE CASCADE ON UPDATE CASCADE;
        END IF;

        -- 3. Domain metadata --------------------------------------------
        SELECT COUNT(*) INTO orphans_metadata
          FROM powerdns.domainmetadata m
          LEFT JOIN powerdns.domains d ON m.domain_id = d.id
          WHERE d.id IS NULL;
        IF orphans_metadata > 0 THEN
            DELETE m FROM powerdns.domainmetadata m
              LEFT JOIN powerdns.domains d ON m.domain_id = d.id
              WHERE d.id IS NULL;
            SELECT CONCAT('Cleaned ', orphans_metadata, ' orphan rows from powerdns.domainmetadata') AS info;
        END IF;

        SELECT COUNT(*) INTO fk_count
          FROM information_schema.TABLE_CONSTRAINTS
          WHERE CONSTRAINT_SCHEMA = 'powerdns'
            AND TABLE_NAME = 'domainmetadata'
            AND CONSTRAINT_TYPE = 'FOREIGN KEY';
        IF fk_count = 0 THEN
            ALTER TABLE powerdns.domainmetadata
              ADD CONSTRAINT fk_domainmetadata_domain
                FOREIGN KEY (domain_id) REFERENCES powerdns.domains(id)
                ON DELETE CASCADE ON UPDATE CASCADE;
        END IF;

        -- 4. Cryptokeys -------------------------------------------------
        SELECT COUNT(*) INTO orphans_cryptokeys
          FROM powerdns.cryptokeys k
          LEFT JOIN powerdns.domains d ON k.domain_id = d.id
          WHERE d.id IS NULL;
        IF orphans_cryptokeys > 0 THEN
            DELETE k FROM powerdns.cryptokeys k
              LEFT JOIN powerdns.domains d ON k.domain_id = d.id
              WHERE d.id IS NULL;
            SELECT CONCAT('Cleaned ', orphans_cryptokeys, ' orphan rows from powerdns.cryptokeys') AS info;
        END IF;

        SELECT COUNT(*) INTO fk_count
          FROM information_schema.TABLE_CONSTRAINTS
          WHERE CONSTRAINT_SCHEMA = 'powerdns'
            AND TABLE_NAME = 'cryptokeys'
            AND CONSTRAINT_TYPE = 'FOREIGN KEY';
        IF fk_count = 0 THEN
            ALTER TABLE powerdns.cryptokeys
              ADD CONSTRAINT fk_cryptokeys_domain
                FOREIGN KEY (domain_id) REFERENCES powerdns.domains(id)
                ON DELETE CASCADE ON UPDATE CASCADE;
        END IF;
    END IF;
END//

DELIMITER ;

CALL whp_pdns_add_cascade_fks();

DROP PROCEDURE IF EXISTS whp_pdns_add_cascade_fks;
