-- PostgreSQL function to export table data with TAB-delimited columns
-- Parameters:
--   p_table_name: Name of the table to export
--   p_skip_rows: Number of rows to skip (0-based, so 0 means start from first row)
--   p_file_size_limit: Maximum number of characters to export (file size limit)
--   p_max_lines_per_file: Maximum number of lines (records) per batch (default: 30000)
-- Usage: SELECT * FROM export_job_info('job_info_1', 0, 1000000, 30000);  -- Export job_info_1 table
--        SELECT * FROM export_job_info('job_info_2', 100, 1000000, 30000); -- Export job_info_2 table, skip 100 rows

CREATE OR REPLACE FUNCTION export_job_info(
    p_table_name TEXT,
    p_skip_rows INTEGER DEFAULT 0,
    p_file_size_limit INTEGER DEFAULT 10000000,
    p_max_lines_per_file INTEGER DEFAULT 30000
)
RETURNS TABLE(record_data TEXT)
LANGUAGE plpgsql
AS $$
DECLARE
	DELIMITER_START text := '#@45>';
	DELIMITER_END text   := '<45@#';
	DELIMITER_EOL text   := '[#@!]';
    v_cursor REFCURSOR;
    v_rec RECORD;
    v_total_chars INTEGER := 0;
    v_line_count INTEGER := 0;
    v_current_line_length INTEGER;
    v_query TEXT;
    v_output_text TEXT;
    v_log_text TEXT;
    v_dynamic_query TEXT;
    v_lookup_table TEXT;
    v_ctm_lookup TEXT;
    v_folder_lookup TEXT;
    v_application_lookup TEXT;
    v_sub_app_lookup TEXT;
    v_library_lookup TEXT;
    v_node_group_lookup TEXT;
    v_node_id_lookup TEXT;
    v_application_type_lookup TEXT;
    v_app_form_lookup TEXT;
BEGIN
    -- Get the lookup table name from partitions table, default to 'lookup' if not found
    SELECT lookup_table INTO v_lookup_table FROM partitions WHERE table_name = p_table_name;
    IF v_lookup_table IS NULL OR v_lookup_table = '' THEN
        v_lookup_table := 'lookup';
    END IF;
    
    -- Build the dynamic query to fetch all fields in same order as arc_pg_jobinfo_export.sql
    -- IMPORTANT: ORDER BY is required for cursor stability during pagination!
    -- Without ORDER BY, MOVE FORWARD can skip rows or return duplicates
    -- Column order matches primary key (order_id, ctm_id, rerun_counter) for index usage
    v_query := format(
        'SELECT order_id, ctm_id, rerun_counter, folder_id, job_name, 
                application_id, sub_app_id, library_id, owner, rba, 
                node_group_id, node_id_id, end_time, ended_status, run_time_sec, 
                stat_cal_ctm, stat_cal, stat_period, cpu_time, agent_elapsed_time, 
                workloads, order_date, deletion_date, collection_time, job_id, 
                mem_name, mem_lib, critical, cyclic, description, 
                nje_node, cmd_line, rule_name, output_table, output_size, 
                log_size, log_table, task_type, application_type_id, app_form_id, 
                cm_data, collection_status, failure_state
         FROM %I
         WHERE EXISTS (SELECT 1 FROM rules r WHERE r.name = %I.rule_name)
         ORDER BY order_id, ctm_id, rerun_counter',
        p_table_name,
        p_table_name
    );
    
    -- Open cursor for the query
    OPEN v_cursor FOR EXECUTE v_query;
    
    -- Skip the specified number of rows
    IF p_skip_rows > 0 THEN
        MOVE FORWARD p_skip_rows FROM v_cursor;
    END IF;
    
    -- Fetch rows until we reach the file size limit
    LOOP
        FETCH v_cursor INTO v_rec;
        EXIT WHEN NOT FOUND;
        
        -- Build dynamic query to get chunk_text from the appropriate output table
        v_dynamic_query := format(
            'SELECT string_agg(chunk_text, '''' ORDER BY chunk_no ASC) ' ||
            'FROM %I ' ||
            'WHERE ctm_id = %L AND order_id = %L AND rerun_counter = %L',
            COALESCE(v_rec.output_table, 'job_output'),
            v_rec.ctm_id,
            v_rec.order_id,
            v_rec.rerun_counter
        );
        
        -- Execute the dynamic query to get the output text
        EXECUTE v_dynamic_query INTO v_output_text;
        
        -- Build dynamic query to get log chunk_text from the appropriate log table (last ~0.9MB)
        v_dynamic_query := format(
            'SELECT string_agg(chunk_text, '''' ORDER BY chunk_no ASC) ' ||
            'FROM ( ' ||
            '  SELECT chunk_text, chunk_no ' ||
            '  FROM ( ' ||
            '    SELECT chunk_text, chunk_no, ' ||
            '           SUM(LENGTH(chunk_text)) OVER (ORDER BY chunk_no DESC) as running_total ' ||
            '    FROM %I ' ||
            '    WHERE ctm_id = %L AND order_id = %L AND rerun_counter = %L ' ||
            '  ) inner_sub ' ||
            '  WHERE running_total <= 943718 ' ||
            ') sub',
            COALESCE(v_rec.log_table, 'job_log'),
            v_rec.ctm_id,
            v_rec.order_id,
            v_rec.rerun_counter
        );
        
        -- Execute the dynamic query to get the log text
        EXECUTE v_dynamic_query INTO v_log_text;
        
        -- Get lookup values for all foreign key fields using dynamic lookup table name
        EXECUTE format('SELECT field_value FROM %I WHERE field_id = $1 AND field_name = $2', v_lookup_table) INTO v_ctm_lookup USING v_rec.ctm_id, 'ctm_id';
        EXECUTE format('SELECT field_value FROM %I WHERE field_id = $1 AND field_name = $2', v_lookup_table) INTO v_folder_lookup USING v_rec.folder_id, 'folder_id';
        EXECUTE format('SELECT field_value FROM %I WHERE field_id = $1 AND field_name = $2', v_lookup_table) INTO v_application_lookup USING v_rec.application_id, 'application_id';
        EXECUTE format('SELECT field_value FROM %I WHERE field_id = $1 AND field_name = $2', v_lookup_table) INTO v_sub_app_lookup USING v_rec.sub_app_id, 'sub_app_id';
        EXECUTE format('SELECT field_value FROM %I WHERE field_id = $1 AND field_name = $2', v_lookup_table) INTO v_library_lookup USING v_rec.library_id, 'library_id';
        EXECUTE format('SELECT field_value FROM %I WHERE field_id = $1 AND field_name = $2', v_lookup_table) INTO v_node_group_lookup USING v_rec.node_group_id, 'node_group_id';
        EXECUTE format('SELECT field_value FROM %I WHERE field_id = $1 AND field_name = $2', v_lookup_table) INTO v_node_id_lookup USING v_rec.node_id_id, 'node_id_id';
        EXECUTE format('SELECT field_value FROM %I WHERE field_id = $1 AND field_name = $2', v_lookup_table) INTO v_application_type_lookup USING v_rec.application_type_id, 'application_type_id';
        EXECUTE format('SELECT field_value FROM %I WHERE field_id = $1 AND field_name = $2', v_lookup_table) INTO v_app_form_lookup USING v_rec.app_form_id, 'app_form_id';
        
        -- Build the final record with all fields in same order as arc_pg_jobinfo_export.sql
        record_data := 
            DELIMITER_START || COALESCE(v_rec.order_id, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_ctm_lookup, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.rerun_counter::text, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_folder_lookup, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.job_name, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_application_lookup, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_sub_app_lookup, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_library_lookup, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.owner, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.rba, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_node_group_lookup, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_node_id_lookup, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.end_time::text, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.ended_status::text, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.run_time_sec::text, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.stat_cal_ctm, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.stat_cal, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.stat_period, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.cpu_time::text, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.agent_elapsed_time::text, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.workloads, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.order_date, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.deletion_date::text, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.collection_time::text, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.job_id, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.mem_name, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.mem_lib, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.critical, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.cyclic, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(REPLACE(v_rec.description, '''', ''''''), '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.nje_node, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(REPLACE(v_rec.cmd_line, '''', ''''''), '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.rule_name, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.output_table, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.output_size::text, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.log_size::text, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.log_table, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.task_type::text, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_application_type_lookup, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_app_form_lookup, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.cm_data, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.collection_status::text, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_rec.failure_state, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_log_text, '') || DELIMITER_END || E'\t' ||
            DELIMITER_START || COALESCE(v_output_text, '') || DELIMITER_END || E'\t' || DELIMITER_EOL;
        
        -- Calculate length of current line (including newline character)
        v_current_line_length := LENGTH(record_data) + 1;
        
        -- Check if adding this record would exceed the limit (but always return at least one record)
        IF v_total_chars > 0 AND v_total_chars + v_current_line_length > p_file_size_limit THEN
            EXIT;
        END IF;
        IF v_line_count >= p_max_lines_per_file THEN
            EXIT;
        END IF;
        
        RETURN NEXT;
        
        v_total_chars := v_total_chars + v_current_line_length;
        v_line_count := v_line_count + 1;
    END LOOP;
    
    -- Close cursor
    CLOSE v_cursor;
END;
$$;
