{% macro snapshot_staging_table(strategy, source_sql, target_relation) -%}

    with snapshot_query as (

        {{ source_sql }}

    ),

    snapshotted_data as (

        select t.*,
            {{ strategy.unique_key }} as dbt_unique_key

        from {{ target_relation }} t
        where dbt_valid_to is null

    ),

    insertions_source_data as (

        select
            sq.*,
            {{ strategy.unique_key }} as dbt_unique_key,
            {{ strategy.updated_at }} as dbt_updated_at,
            {{ strategy.updated_at }} as dbt_valid_from,
            CAST(nullif({{ strategy.updated_at }}, {{ strategy.updated_at }}) AS TIMESTAMP(9)) as dbt_valid_to,
            {{ strategy.scd_id }} as dbt_scd_id

        from snapshot_query sq
    ),

    updates_source_data as (

        select
            sq.*,
            {{ strategy.unique_key }} as dbt_unique_key,
            {{ strategy.updated_at }} as dbt_updated_at,
            {{ strategy.updated_at }} as dbt_valid_from,
            {{ strategy.updated_at }} as dbt_valid_to

        from snapshot_query sq
    ),

    {%- if strategy.invalidate_hard_deletes %}

    deletes_source_data as (

        select
            sq.*,
            {{ strategy.unique_key }} as dbt_unique_key
        from snapshot_query sq
    ),
    {% endif %}

    insertions as (

        select
            'insert' as dbt_change_type,
            source_data.*

        from insertions_source_data source_data
        left outer join snapshotted_data on snapshotted_data.dbt_unique_key = source_data.dbt_unique_key
        where snapshotted_data.dbt_unique_key is null
           or (
            snapshotted_data.dbt_unique_key is not null
            and (
                {{ strategy.row_changed }}
            )
        )

    ),

    updates as (

        select
            'update' as dbt_change_type,
            source_data.*,
            snapshotted_data.dbt_scd_id

        from updates_source_data source_data
        join snapshotted_data on snapshotted_data.dbt_unique_key = source_data.dbt_unique_key
        where (
            {{ strategy.row_changed }}
        )
    )
    {%- if strategy.invalidate_hard_deletes -%}
    ,

    deletes as (

        select
            'delete' as dbt_change_type,
            source_data.*,
            TO_TIMESTAMP({{ snapshot_get_time() }}) as dbt_valid_from,
            TO_TIMESTAMP({{ snapshot_get_time() }}) as dbt_updated_at,
            TO_TIMESTAMP({{ snapshot_get_time() }}) as dbt_valid_to,
            snapshotted_data.dbt_scd_id

        from snapshotted_data
        left join deletes_source_data source_data on snapshotted_data.dbt_unique_key = source_data.dbt_unique_key
        where source_data.dbt_unique_key is null
    )
    {%- endif %}

    select * from insertions
    union all
    select * from updates
    {%- if strategy.invalidate_hard_deletes %}
    union all
    select * from deletes
    {%- endif %}

{%- endmacro %}


{% macro build_snapshot_table(strategy, sql) %}

    select sbq.*,
        {{ strategy.scd_id }} as dbt_scd_id,
        {{ strategy.updated_at }} as dbt_updated_at,
        {{ strategy.updated_at }} as dbt_valid_from,
        CAST(nullif({{ strategy.updated_at }}, {{ strategy.updated_at }}) AS TIMESTAMP(9)) as dbt_valid_to
    from (
        {{ sql }}
    ) sbq

{% endmacro %}


{% macro oracle__snapshot_merge_sql(target, source, insert_cols) -%}
    {%- set insert_cols_csv = insert_cols | join(', ') -%}

    UPDATE {{ target }} DBT_INTERNAL_DEST
    SET dbt_valid_to = (
        SELECT
            DBT_INTERNAL_SOURCE.dbt_valid_to
        FROM
            {{ source }} DBT_INTERNAL_SOURCE
        WHERE
            DBT_INTERNAL_SOURCE.dbt_scd_id = DBT_INTERNAL_DEST.dbt_scd_id
            AND DBT_INTERNAL_SOURCE.dbt_change_type IN ('update', 'delete')
    )
    WHERE
        DBT_INTERNAL_DEST.dbt_valid_to is null;

    INSERT INTO {{ target }} ({{ insert_cols_csv }})
    SELECT
        {% for column in insert_cols -%}
            DBT_INTERNAL_SOURCE.{{ column }} {%- if not loop.last %}, {%- endif %}
        {%- endfor %}
    FROM
        {{ source }} DBT_INTERNAL_SOURCE
    WHERE
        DBT_INTERNAL_SOURCE.dbt_change_type = 'insert';
{% endmacro %}

{% macro build_snapshot_staging_table(strategy, sql, target_relation) %}
    {% set tmp_relation = make_temp_relation(target_relation) %}

    {% set select = snapshot_staging_table(strategy, sql, target_relation) %}

    {% set result = run_query(select) %}
    {% do result.print_table() %}

    {% call statement('build_snapshot_staging_relation') %}
        {{ create_table_as(True, tmp_relation, select) }}
    {% endcall %}

    {% do return(tmp_relation) %}
{% endmacro %}


{% macro oracle__snapshot_hash_arguments(args) -%}
    RAWTOHEX(
        standard_hash(
            {%- for arg in args -%}
                coalesce(cast({{ arg }} as VARCHAR2(4000 CHAR) ), '') {% if not loop.last %} || '|' || {% endif %}
            {%- endfor -%},
            'MD5'
        )
    )
{%- endmacro %}

