-- ============================================================================
-- MARS-1409-POSTHOOK Step 01: Update A_WORKFLOW_HISTORY_KEY for existing records
-- ============================================================================
-- Purpose: Populate A_WORKFLOW_HISTORY_KEY for existing A_SOURCE_FILE_RECEIVED records
--          by extracting values from corresponding ODS tables
-- Author: Grzegorz Michalski
-- Date: 2026-03-13
-- Prerequisites: 
--   - MARS-1409 installed (A_WORKFLOW_HISTORY_KEY column exists in A_SOURCE_FILE_RECEIVED)
--   - ODS tables contain A_WORKFLOW_HISTORY_KEY and file$name columns
-- ============================================================================

SET SERVEROUTPUT ON SIZE UNLIMITED
WHENEVER SQLERROR EXIT SQL.SQLCODE

PROMPT
PROMPT Updating A_WORKFLOW_HISTORY_KEY for existing A_SOURCE_FILE_RECEIVED records...

DECLARE
    vUpdatedTotal       NUMBER := 0;
    vUpdatedCurrent     NUMBER := 0;
    vFailedConfigs      NUMBER := 0;
    vTableNotFound      NUMBER := 0;
    vSkippedConfigs     NUMBER := 0;
    vEmptyTables        NUMBER := 0;
    vHasData            NUMBER := 0;
    vTableName          VARCHAR2(200);
    vSQL                VARCHAR2(32767);
    vRecordsToUpdate    NUMBER := 0;
    vRemainingTargeted  NUMBER := 0;
    vTableExists        NUMBER := 0;

BEGIN
    -- Count total records to update
    SELECT COUNT(*) INTO vRecordsToUpdate
    FROM CT_MRDS.A_SOURCE_FILE_RECEIVED
    WHERE A_WORKFLOW_HISTORY_KEY IS NULL
      AND PROCESSING_STATUS IN ('VALIDATED', 'READY_FOR_INGESTION', 'INGESTED', 'ARCHIVED', 'ARCHIVED_AND_TRASHED', 'ARCHIVED_AND_PURGED');
    
    DBMS_OUTPUT.PUT_LINE('Found ' || vRecordsToUpdate || ' records with NULL A_WORKFLOW_HISTORY_KEY');
    DBMS_OUTPUT.PUT_LINE('----------------------------------------');
    
    -- Process each INPUT configuration that has records to update
    FOR config_rec IN (
        SELECT 
            sfc.A_SOURCE_FILE_CONFIG_KEY,
            sfc.A_SOURCE_KEY,
            sfc.SOURCE_FILE_ID,
            sfc.TABLE_ID,
            sfc.TEMPLATE_TABLE_NAME,
            (SELECT COUNT(*) 
             FROM CT_MRDS.A_SOURCE_FILE_RECEIVED sfr 
             WHERE sfr.A_SOURCE_FILE_CONFIG_KEY = sfc.A_SOURCE_FILE_CONFIG_KEY
               AND sfr.A_WORKFLOW_HISTORY_KEY IS NULL
               AND sfr.PROCESSING_STATUS IN ('VALIDATED', 'READY_FOR_INGESTION', 'INGESTED', 'ARCHIVED', 'ARCHIVED_AND_TRASHED', 'ARCHIVED_AND_PURGED')
            ) AS NULL_COUNT
        FROM CT_MRDS.A_SOURCE_FILE_CONFIG sfc
        WHERE sfc.SOURCE_FILE_TYPE = 'INPUT'
          AND sfc.TABLE_ID IS NOT NULL
        ORDER BY sfc.A_SOURCE_KEY, sfc.SOURCE_FILE_ID, sfc.TABLE_ID
    ) LOOP
        
        IF config_rec.NULL_COUNT = 0 THEN
            vSkippedConfigs := vSkippedConfigs + 1;
            DBMS_OUTPUT.PUT_LINE('SKIP: Config ' || config_rec.A_SOURCE_FILE_CONFIG_KEY || 
                               ' (' || config_rec.A_SOURCE_KEY || '/' || config_rec.SOURCE_FILE_ID || '/' || config_rec.TABLE_ID || 
                               ') - no records to update');
            CONTINUE;
        END IF;
        
        BEGIN
            -- Construct ODS table name from TABLE_ID (ODS tables have _ODS suffix)
            vTableName := 'ODS.' || config_rec.TABLE_ID || '_ODS';

            -- Check table existence before attempting dynamic SQL
            SELECT COUNT(*) INTO vTableExists
            FROM ALL_TABLES
            WHERE OWNER = 'ODS'
              AND TABLE_NAME = config_rec.TABLE_ID || '_ODS';

            IF vTableExists = 0 THEN
                vTableNotFound := vTableNotFound + 1;
                DBMS_OUTPUT.PUT_LINE('SKIP: Config ' || config_rec.A_SOURCE_FILE_CONFIG_KEY ||
                                   ' (' || config_rec.A_SOURCE_KEY || '/' || config_rec.SOURCE_FILE_ID || '/' || config_rec.TABLE_ID ||
                                   ') - ODS table not found: ' || vTableName);
                CONTINUE;
            END IF;

            -- Pre-check: verify ODS table has accessible data (empty external table throws ORA-29913/KUP-05002)
            vHasData := 0;
            BEGIN
                EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM (SELECT 1 FROM ' || vTableName || ' t WHERE ROWNUM = 1)'
                    INTO vHasData;
            EXCEPTION
                WHEN OTHERS THEN
                    IF SQLCODE = -29913 OR INSTR(SQLERRM, 'KUP-05002') > 0 THEN
                        NULL; -- vHasData stays 0
                    ELSE
                        RAISE;
                    END IF;
            END;

            IF vHasData = 0 THEN
                vEmptyTables := vEmptyTables + 1;
                DBMS_OUTPUT.PUT_LINE('SKIP: Config ' || config_rec.A_SOURCE_FILE_CONFIG_KEY ||
                                   ' (' || config_rec.A_SOURCE_KEY || '/' || config_rec.SOURCE_FILE_ID || '/' || config_rec.TABLE_ID ||
                                   ') - ODS table has no files at storage location (empty): ' || vTableName);
                CONTINUE;
            END IF;

            DBMS_OUTPUT.PUT_LINE('Processing config ' || config_rec.A_SOURCE_FILE_CONFIG_KEY || 
                               ' (' || config_rec.A_SOURCE_KEY || '/' || config_rec.SOURCE_FILE_ID || '/' || config_rec.TABLE_ID || ')...');
            
            -- Update using ODS table
            -- NO_PARALLEL hint required: ODS external tables (OCI Object Storage) fail with ORA-12801 under parallel query
            vSQL := 
                'UPDATE CT_MRDS.A_SOURCE_FILE_RECEIVED sfr ' ||
                'SET A_WORKFLOW_HISTORY_KEY = ( ' ||
                '    SELECT /*+ NO_PARALLEL(t) */ t.A_WORKFLOW_HISTORY_KEY ' ||
                '    FROM ' || vTableName || ' t ' ||
                '    WHERE t.file$name = sfr.SOURCE_FILE_NAME ' ||
                '      AND rownum=1 ' ||
                ') ' ||
                'WHERE sfr.A_SOURCE_FILE_CONFIG_KEY = :config_key ' ||
                '  AND sfr.A_WORKFLOW_HISTORY_KEY IS NULL ' ||
                '  AND sfr.PROCESSING_STATUS IN (''VALIDATED'', ''READY_FOR_INGESTION'', ''INGESTED'', ''ARCHIVED'', ''ARCHIVED_AND_TRASHED'', ''ARCHIVED_AND_PURGED'') ' ||
                '  AND EXISTS ( ' ||
                '      SELECT /*+ NO_PARALLEL(t) */ 1 FROM ' || vTableName || ' t ' ||
                '      WHERE t.file$name = sfr.SOURCE_FILE_NAME ' ||
                '        AND rownum=1 ' ||
                '  )';
            
            EXECUTE IMMEDIATE vSQL USING config_rec.A_SOURCE_FILE_CONFIG_KEY;
            commit;
            vUpdatedCurrent := SQL%ROWCOUNT;
            vUpdatedTotal := vUpdatedTotal + vUpdatedCurrent;
            
            IF vUpdatedCurrent > 0 THEN
                DBMS_OUTPUT.PUT_LINE('  SUCCESS: Updated ' || vUpdatedCurrent || ' record(s)');
            ELSE
                DBMS_OUTPUT.PUT_LINE('  INFO: No matching records found in ODS table (files may not be ingested yet)');
            END IF;
            
        EXCEPTION
            WHEN OTHERS THEN
                vFailedConfigs := vFailedConfigs + 1;
                DBMS_OUTPUT.PUT_LINE('  ERROR: Unexpected failure for config ' || config_rec.A_SOURCE_FILE_CONFIG_KEY || 
                                   ' (table: ' || vTableName || ')');
                DBMS_OUTPUT.PUT_LINE('  Reason: ' || SQLERRM);
                -- Continue processing other configurations despite this failure
        END;
    END LOOP;
    
    COMMIT;
    
    DBMS_OUTPUT.PUT_LINE('----------------------------------------');
    DBMS_OUTPUT.PUT_LINE('Update Summary:');
    DBMS_OUTPUT.PUT_LINE('  Total records updated: ' || vUpdatedTotal);
    DBMS_OUTPUT.PUT_LINE('  Configurations skipped (no NULL records): ' || vSkippedConfigs);
    DBMS_OUTPUT.PUT_LINE('  Configurations skipped (ODS table not found): ' || vTableNotFound);
    DBMS_OUTPUT.PUT_LINE('  Configurations skipped (ODS table empty - no files at location): ' || vEmptyTables);
    DBMS_OUTPUT.PUT_LINE('  Configurations failed (unexpected errors): ' || vFailedConfigs);
    
    -- Check remaining NULL records - targeted statuses only
    SELECT COUNT(*) INTO vRemainingTargeted
    FROM CT_MRDS.A_SOURCE_FILE_RECEIVED
    WHERE A_WORKFLOW_HISTORY_KEY IS NULL
      AND PROCESSING_STATUS IN ('VALIDATED', 'READY_FOR_INGESTION', 'INGESTED', 'ARCHIVED', 'ARCHIVED_AND_TRASHED', 'ARCHIVED_AND_PURGED');

    -- Check all remaining NULL records (includes RECEIVED, VALIDATION_FAILED)
    SELECT COUNT(*) INTO vRecordsToUpdate
    FROM CT_MRDS.A_SOURCE_FILE_RECEIVED
    WHERE A_WORKFLOW_HISTORY_KEY IS NULL;

    DBMS_OUTPUT.PUT_LINE('  Remaining NULL records (targeted statuses): ' || vRemainingTargeted);
    DBMS_OUTPUT.PUT_LINE('  Remaining NULL records (all statuses):      ' || vRecordsToUpdate);
    
    IF vRemainingTargeted > 0 THEN
        DBMS_OUTPUT.PUT_LINE('');
        DBMS_OUTPUT.PUT_LINE('NOTE: Some records with targeted statuses still have NULL A_WORKFLOW_HISTORY_KEY.');
        DBMS_OUTPUT.PUT_LINE('      This is expected for files not yet ingested into ODS tables');
        DBMS_OUTPUT.PUT_LINE('      or ODS tables with a different structure.');
        DBMS_OUTPUT.PUT_LINE('      These records will be populated when files are re-processed.');
    END IF;

    IF vFailedConfigs > 0 THEN
        DBMS_OUTPUT.PUT_LINE('');
        DBMS_OUTPUT.PUT_LINE('NOTE: ' || vFailedConfigs || ' configuration(s) failed with unexpected errors.');
        DBMS_OUTPUT.PUT_LINE('      Review the ERROR lines above and investigate manually.');
    END IF;

    DBMS_OUTPUT.PUT_LINE('----------------------------------------');
    
EXCEPTION
    WHEN OTHERS THEN
        ROLLBACK;
        DBMS_OUTPUT.PUT_LINE('FATAL ERROR: ' || SQLERRM);
        DBMS_OUTPUT.PUT_LINE('Transaction rolled back');
        RAISE;
END;
/

PROMPT
PROMPT Existing workflow keys update completed!
PROMPT

-- ============================================================================
-- Step 2: Set PROCESSING_STATUS = 'INGESTED' for records whose workflow
--         completed successfully (mirrors trigger A_WORKFLOW_HISTORY logic)
-- ============================================================================
PROMPT
PROMPT Updating PROCESSING_STATUS to INGESTED for completed workflows...

DECLARE
    vUpdatedIngested    NUMBER := 0;
BEGIN
    UPDATE CT_MRDS.A_SOURCE_FILE_RECEIVED sfr
    SET    sfr.PROCESSING_STATUS = 'INGESTED',
           sfr.PROCESS_NAME      = (
               SELECT wh.service_name
               FROM   CT_MRDS.A_WORKFLOW_HISTORY wh
               WHERE  wh.a_workflow_history_key = sfr.a_workflow_history_key
           )
    WHERE  sfr.A_WORKFLOW_HISTORY_KEY IS NOT NULL
      AND  sfr.PROCESSING_STATUS IN ('READY_FOR_INGESTION')
      AND  EXISTS (
               SELECT 1
               FROM   CT_MRDS.A_WORKFLOW_HISTORY wh
               WHERE  wh.a_workflow_history_key = sfr.a_workflow_history_key
                 AND  wh.workflow_successful     = 'Y'
           );

    vUpdatedIngested := SQL%ROWCOUNT;
    COMMIT;

    DBMS_OUTPUT.PUT_LINE('Updated PROCESSING_STATUS to INGESTED: ' || vUpdatedIngested || ' record(s)');

EXCEPTION
    WHEN OTHERS THEN
        ROLLBACK;
        DBMS_OUTPUT.PUT_LINE('FATAL ERROR: ' || SQLERRM);
        DBMS_OUTPUT.PUT_LINE('Transaction rolled back');
        RAISE;
END;
/

PROMPT
PROMPT INGESTED status update completed!
PROMPT
