/*
 * Repairs and normalizes tachograph driver identities after introducing:
 * - global eventhub.driver
 * - global eventhub.driver_card
 * - source_driver_identity
 * - source_driver_card_identity
 *
 * What it does:
 * 1. Ensures tachograph DRIVER master-data payload carries last_name while
 *    keeping source_master_entity.display_name unchanged.
 * 2. Upserts global eventhub.driver rows from tachograph DRIVER entities.
 * 3. Upserts global eventhub.driver_card rows from tachograph DRIVER_CARD entities.
 * 4. Upserts source identity links for drivers and cards.
 * 5. Links cards to drivers using DRIVER_CARD_DRIVER master-data relations.
 * 6. Backfills event.driver_card_id where a driver has exactly one card.
 * 7. Remaps event.driver_id from provisional rows to the linked canonical driver.
 * 8. Deletes now-unreferenced provisional driver rows.
 */

with master_sources as (
    select es.id, es.tenant_key
    from eventhub.event_source es
    where es.provider_key = 'TACHOGRAPH'
      and es.source_kind = 'MASTER_DATA'
      and es.source_key = 'TACHOGRAPH_MASTER_DATA'
),
updated_master_payload as (
    update eventhub.source_master_entity sme
       set payload = jsonb_strip_nulls(
           sme.payload
           || jsonb_build_object(
                'first_names', coalesce(sme.payload ->> 'first_names', sme.payload ->> 'firstnames'),
                'last_name', coalesce(sme.payload ->> 'last_name', sme.payload ->> 'surname')
              )
       ),
           updated_at = now()
      from master_sources ms
     where sme.tenant_key = ms.tenant_key
       and sme.event_source_id = ms.id
       and sme.entity_type = 'DRIVER'
    returning sme.id
)
select count(*) as updated_master_payload
from updated_master_payload;

with master_sources as (
    select es.id as master_event_source_id, es.tenant_key
    from eventhub.event_source es
    where es.provider_key = 'TACHOGRAPH'
      and es.source_kind = 'MASTER_DATA'
      and es.source_key = 'TACHOGRAPH_MASTER_DATA'
),
master_drivers as (
    select ms.master_event_source_id,
           ms.tenant_key,
           d.source_entity_id as source_driver_entity_id,
           coalesce(nullif(trim(d.payload ->> 'first_names'), ''), nullif(trim(d.payload ->> 'firstnames'), '')) as first_names,
           coalesce(nullif(trim(d.payload ->> 'last_name'), ''), nullif(trim(d.payload ->> 'surname'), '')) as last_name,
           cast(nullif(trim(d.payload ->> 'birth_date'), '') as date) as birth_date,
           d.source_updated_at,
           d.payload
    from master_sources ms
    join eventhub.source_master_entity d
      on d.tenant_key = ms.tenant_key
     and d.event_source_id = ms.master_event_source_id
     and d.entity_type = 'DRIVER'
),
resolved_drivers as (
    select md.*,
           coalesce(identity.driver_id, gen_random_uuid()) as driver_id
    from master_drivers md
    left join eventhub.source_driver_identity identity
      on identity.tenant_key = md.tenant_key
     and identity.event_source_id = md.master_event_source_id
     and identity.source_driver_entity_id = md.source_driver_entity_id
),
inserted_drivers as (
    insert into eventhub.driver(
        id, first_names, last_name, birth_date, source_updated_at, payload, updated_at
    )
    select distinct on (rd.driver_id)
           rd.driver_id,
           rd.first_names,
           rd.last_name,
           rd.birth_date,
           rd.source_updated_at,
           rd.payload,
           now()
    from resolved_drivers rd
    where not exists (
        select 1
        from eventhub.driver existing
        where existing.id = rd.driver_id
    )
    returning id
),
updated_drivers as (
    update eventhub.driver driver
       set first_names = coalesce(rd.first_names, driver.first_names),
           last_name = coalesce(rd.last_name, driver.last_name),
           birth_date = coalesce(rd.birth_date, driver.birth_date),
           source_updated_at = coalesce(rd.source_updated_at, driver.source_updated_at),
           payload = driver.payload || rd.payload,
           updated_at = now()
      from resolved_drivers rd
     where driver.id = rd.driver_id
    returning driver.id
),
upserted_source_driver_identity as (
    insert into eventhub.source_driver_identity(
        id, tenant_key, event_source_id, source_driver_entity_id,
        driver_id, source_updated_at, payload, updated_at
    )
    select gen_random_uuid(),
           rd.tenant_key,
           rd.master_event_source_id,
           rd.source_driver_entity_id,
           rd.driver_id,
           rd.source_updated_at,
           rd.payload,
           now()
    from resolved_drivers rd
    on conflict (tenant_key, event_source_id, source_driver_entity_id)
    do update set
        driver_id = excluded.driver_id,
        source_updated_at = coalesce(excluded.source_updated_at, eventhub.source_driver_identity.source_updated_at),
        payload = eventhub.source_driver_identity.payload || excluded.payload,
        updated_at = now()
    returning id
)
select (select count(*) from inserted_drivers) as inserted_drivers,
       (select count(*) from updated_drivers) as updated_drivers,
       (select count(*) from upserted_source_driver_identity) as upserted_source_driver_identity;

with master_sources as (
    select es.id as master_event_source_id, es.tenant_key
    from eventhub.event_source es
    where es.provider_key = 'TACHOGRAPH'
      and es.source_kind = 'MASTER_DATA'
      and es.source_key = 'TACHOGRAPH_MASTER_DATA'
),
master_cards as (
    select ms.master_event_source_id,
           ms.tenant_key,
           card.source_entity_id as source_driver_card_entity_id,
           nullif(trim(card.payload ->> 'card_nation'), '') as card_nation,
           nullif(trim(card.payload ->> 'card_number'), '') as card_number,
           card.source_updated_at,
           card.payload
    from master_sources ms
    join eventhub.source_master_entity card
      on card.tenant_key = ms.tenant_key
     and card.event_source_id = ms.master_event_source_id
     and card.entity_type = 'DRIVER_CARD'
     and nullif(trim(card.payload ->> 'card_nation'), '') is not null
     and nullif(trim(card.payload ->> 'card_number'), '') is not null
),
canonical_driver_cards as (
    select distinct on (mc.card_nation, mc.card_number)
           mc.card_nation,
           mc.card_number,
           mc.source_updated_at,
           mc.payload
    from master_cards mc
    order by mc.card_nation,
             mc.card_number,
             case when mc.source_driver_card_entity_id is null then 1 else 0 end,
             mc.source_updated_at desc,
             mc.source_driver_card_entity_id
),
existing_driver_cards as (
    select distinct on (card.nation, card.card_number)
           card.id,
           card.nation,
           card.card_number
    from eventhub.driver_card card
    order by card.nation,
             card.card_number,
             case when card.driver_id is null then 1 else 0 end,
             card.updated_at desc,
             card.created_at desc,
             card.id
),
resolved_cards as (
    select canonical.card_nation,
           canonical.card_number,
           canonical.source_updated_at,
           canonical.payload,
           coalesce(existing.id, gen_random_uuid()) as driver_card_id
    from canonical_driver_cards canonical
    left join existing_driver_cards existing
      on existing.nation = canonical.card_nation
     and existing.card_number = canonical.card_number
),
inserted_cards as (
    insert into eventhub.driver_card(
        id, driver_id, nation, card_number, source_updated_at, payload, updated_at
    )
    select distinct on (rc.driver_card_id)
           rc.driver_card_id,
           null,
           rc.card_nation,
           rc.card_number,
           rc.source_updated_at,
           rc.payload,
           now()
    from resolved_cards rc
    where not exists (
        select 1
        from eventhub.driver_card existing
        where existing.id = rc.driver_card_id
    )
    returning id
),
updated_cards as (
    update eventhub.driver_card card
       set source_updated_at = coalesce(rc.source_updated_at, card.source_updated_at),
           payload = card.payload || rc.payload,
           updated_at = now()
      from resolved_cards rc
     where card.id = rc.driver_card_id
    returning card.id
),
upserted_source_driver_card_identity as (
    insert into eventhub.source_driver_card_identity(
        id, tenant_key, event_source_id, source_driver_card_entity_id,
        driver_card_id, source_updated_at, payload, updated_at
    )
    select gen_random_uuid(),
           mc.tenant_key,
           mc.master_event_source_id,
           mc.source_driver_card_entity_id,
           coalesce(identity.driver_card_id, existing.id),
           mc.source_updated_at,
           mc.payload,
           now()
    from master_cards mc
    left join eventhub.source_driver_card_identity identity
      on identity.tenant_key = mc.tenant_key
     and identity.event_source_id = mc.master_event_source_id
     and identity.source_driver_card_entity_id = mc.source_driver_card_entity_id
    left join existing_driver_cards existing
      on existing.nation = mc.card_nation
     and existing.card_number = mc.card_number
    where mc.source_driver_card_entity_id is not null
      and coalesce(identity.driver_card_id, existing.id) is not null
    on conflict (tenant_key, event_source_id, source_driver_card_entity_id)
    do update set
        driver_card_id = excluded.driver_card_id,
        source_updated_at = coalesce(excluded.source_updated_at, eventhub.source_driver_card_identity.source_updated_at),
        payload = eventhub.source_driver_card_identity.payload || excluded.payload,
        updated_at = now()
    returning id
)
select (select count(*) from inserted_cards) as inserted_cards,
       (select count(*) from updated_cards) as updated_cards,
       (select count(*) from upserted_source_driver_card_identity) as upserted_source_driver_card_identity;

with master_sources as (
    select es.id as master_event_source_id, es.tenant_key
    from eventhub.event_source es
    where es.provider_key = 'TACHOGRAPH'
      and es.source_kind = 'MASTER_DATA'
      and es.source_key = 'TACHOGRAPH_MASTER_DATA'
),
updated_card_links as (
    update eventhub.driver_card card
       set driver_id = driver_identity.driver_id,
           source_updated_at = coalesce(rel.source_updated_at, card.source_updated_at),
           updated_at = now()
      from master_sources ms
      join eventhub.source_master_relation rel
        on rel.tenant_key = ms.tenant_key
       and rel.event_source_id = ms.master_event_source_id
       and rel.relation_type = 'DRIVER_CARD_DRIVER'
       and rel.from_entity_type = 'DRIVER_CARD'
       and rel.to_entity_type = 'DRIVER'
      join eventhub.source_driver_card_identity card_identity
        on card_identity.tenant_key = rel.tenant_key
       and card_identity.event_source_id = rel.event_source_id
       and card_identity.source_driver_card_entity_id = rel.from_source_entity_id
      join eventhub.source_driver_identity driver_identity
        on driver_identity.tenant_key = rel.tenant_key
       and driver_identity.event_source_id = rel.event_source_id
       and driver_identity.source_driver_entity_id = rel.to_source_entity_id
     where card.id = card_identity.driver_card_id
       and (
           card.driver_id is null
           or card.driver_id = driver_identity.driver_id
           or not exists (
               select 1
               from eventhub.source_driver_identity existing_identity
               where existing_identity.driver_id = card.driver_id
           )
       )
    returning card.id
)
select count(*) as updated_card_links
from updated_card_links;

with single_card_per_driver as (
    select driver_id,
           min(id::text)::uuid as driver_card_id
    from eventhub.driver_card
    where driver_id is not null
    group by driver_id
    having count(*) = 1
),
updated_events as (
    update eventhub.event event
       set driver_card_id = card.driver_card_id
      from single_card_per_driver card
     where event.driver_id = card.driver_id
       and event.driver_card_id is null
    returning event.id
)
select count(*) as backfilled_event_driver_cards
from updated_events;

with remapped_events as (
    update eventhub.event event
       set driver_id = card.driver_id
      from eventhub.driver_card card
     where event.driver_card_id = card.id
       and card.driver_id is not null
       and (
           event.driver_id is null
           or not exists (
               select 1
               from eventhub.source_driver_identity source_identity
               where source_identity.driver_id = event.driver_id
           )
       )
       and event.driver_id is distinct from card.driver_id
    returning event.id
)
select count(*) as remapped_events
from remapped_events;

with deleted_drivers as (
    delete from eventhub.driver driver
    where not exists (
              select 1
              from eventhub.event event
              where event.driver_id = driver.id
          )
      and not exists (
              select 1
              from eventhub.driver_card card
              where card.driver_id = driver.id
          )
      and not exists (
              select 1
              from eventhub.source_driver_identity source_identity
              where source_identity.driver_id = driver.id
          )
    returning driver.id
)
select count(*) as deleted_provisional_drivers
from deleted_drivers;
