-- liquibase formatted sql

-- changeset cyril:update_inventory_lot_line_trigger_after_update splitStatements:false

create definer = current_user trigger `inventory_lot_line_AFTER_UPDATE`
    after update
    on `inventory_lot_line`
    for each row
begin
    declare inventoryId int default -1;

    -- Global Error handling
    declare error_msg text default null;
    declare continue handler for sqlexception, sqlwarning
        begin
            get diagnostics condition 1 error_msg = message_text;
            SET error_msg = coalesce(error_msg, 'Unknown error occurred');
            -- Log the error (specific step logging is handled in each block)
        end;

    -- Set inventory id
    select coalesce(
                   (select i.id
                    from `inventory` i
                             left join `inventory_lot` il on i.itemId = il.itemId
                             left join `item_uom` iu on iu.itemId = il.itemId and iu.baseUnit = true
                             left join `stock_in_line` sil on il.stockInLineId = sil.id
                             left join `purchase_order_line` pol on pol.id = sil.purchaseOrderLineId
                    where il.id = new.inventoryLotId
                      and i.uomId = iu.uomId
                    limit 1),
                   -1
           )
    into inventoryId;

    -- Create temp table
    drop temporary table if exists temp_inventory;

    create temporary table temp_inventory
    (
        oldOnHandQty          decimal(14, 2),
        currentOnHandQty      decimal(14, 2),
        oldOnHoldQty          decimal(14, 2),
        currentOnHoldQty      decimal(14, 2),
        oldUnavailableQty     decimal(14, 2),
        currentUnavailableQty decimal(14, 2),
        currencyId            INT,
        currencyName          varchar(30),
        uomId                 INT,
        itemId                INT,
        price                 decimal(14, 2)
    );

    -- Step 1: Insert into temp table
    insert into temp_inventory (oldOnHandQty, currentOnHandQty, oldOnHoldQty, currentOnHoldQty, oldUnavailableQty,
                                currentUnavailableQty, currencyId, currencyName, uomId, itemId, price)
    select coalesce(coalesce(old.inQty, 0) - coalesce(old.outQty, 0), 0) as oldOnHandQty,
           coalesce(coalesce(new.inQty, 0) - coalesce(new.outQty, 0), 0) as currentOnHandQty,
           coalesce(old.holdQty, 0)                                      as oldOnHoldQty,
           coalesce(new.holdQty, 0)                                      as currentOnHoldQty,
           IF(
                   old.status = 'unavailable',
                   coalesce(old.inQty, 0) - coalesce(old.outQty, 0) - coalesce(old.holdQty, 0),
                   0
           )                                                             as oldUnavailableQty,
           IF(
                   new.status = 'unavailable',
                   coalesce(new.inQty, 0) - coalesce(new.outQty, 0) - coalesce(new.holdQty, 0),
                   0
           )                                                             as currentUnavailableQty,
           c.id                                                          as currencyId,
           coalesce(c.name, 'HKD')                                       as currencyName,
           iu.uomId                                                      as uomId,
           il.itemId                                                     as itemId,
           coalesce(pql.price, 0)                                        as price
    from `inventory_lot` il
             left join `item_uom` iu on iu.itemId = il.itemId and iu.baseUnit = true
             left join `stock_in_line` sil on sil.id = il.stockInLineId
             left join `stock_in` si on si.id = sil.stockInId
             left join `purchase_order_line` pol on pol.id = sil.purchaseOrderLineId
             left join `purchase_order` po on po.id = pol.purchaseOrderId
             left join `purchase_quotation_line` pql on pql.itemId = il.itemId and pql.uomId = pol.uomId
             left join `purchase_quotation` pq on pq.id = pql.purchaseQuotationId
             left join `currency` c on c.id = pq.currencyId
    where il.id = new.inventoryLotId;

    -- Step 2: Insert / Update inventory table
    begin
        declare inventoryErrorMsg text default null;
        declare continue handler for sqlexception, sqlwarning
            begin
                GET diagnostics condition 1 inventoryErrorMsg = message_text;
                SET inventoryErrorMsg = coalesce(inventoryErrorMsg, 'Unknown error occurred');
            end;

        if inventoryId < 0 then
            insert into `inventory` (itemId, onHandQty, onHoldQty, unavailableQty, price, currencyId, cpu, cpuUnit, cpm,
                                     cpmUnit, uomId, status)
            select ti.itemId                      as itemId,
                   ti.currentOnHandQty            as onHandQty,
                   ti.currentOnHoldQty            as onHoldQty,
                   ti.currentUnavailableQty       as unavailableQty,
                   ti.price                       as price,
                   ti.currencyId                  as currencyId,
                   0                              as cpu,
                   ti.currencyName                as cpuUnit,
                   0                              as cpm,
                   ti.currencyName                as cpmUnit,
                   ti.uomId                       as uomId,
                   if(coalesce(ti.currentOnHandQty - ti.currentOnHoldQty - ti.currentUnavailableQty, 0) > 0,
                      'available', 'unavailable') as status
            from `temp_inventory` ti;
        else
            update `inventory` i
                join `temp_inventory` ti on i.itemId = ti.itemId and i.uomId = ti.uomId
            set i.onHandQty      = i.onHandQty - (ti.oldOnHandQty - ti.currentOnHandQty),
                i.onHoldQty      = i.onHoldQty - (ti.oldOnHoldQty - ti.currentOnHoldQty),
                i.unavailableQty = case
                                       when old.status = 'available' and new.status = 'unavailable'
                                           then i.unavailableQty + ti.currentUnavailableQty
                                       when old.status = 'unavailable' and new.status = 'available'
                                           then i.unavailableQty - ti.oldUnavailableQty
                                       when old.status = 'unavailable' and new.status = 'unavailable'
                                           then i.unavailableQty + (ti.currentUnavailableQty - ti.oldUnavailableQty)
                                       else i.unavailableQty
                    end,
                i.price          = ti.price,
                i.currencyId     = ti.currencyId,
                i.cpu            = 0,
                i.cpuUnit        = ti.currencyName,
                i.cpm            = 0,
                i.cpmUnit        = ti.currencyName,
                i.status         = if((i.onHandQty - (ti.oldOnHandQty - ti.currentOnHandQty)) - (i.onHoldQty -
                                      (ti.oldOnHoldQty - ti.currentOnHoldQty))
                                          - (case
                                                when old.status = 'available' and new.status = 'unavailable'
                                                    then i.unavailableQty + ti.currentUnavailableQty
                                                when old.status = 'unavailable' and new.status = 'available'
                                                    then i.unavailableQty - ti.oldUnavailableQty
                                                when old.status = 'unavailable' and new.status = 'unavailable'
                                                    then i.unavailableQty + (ti.currentUnavailableQty - ti.oldUnavailableQty)
                                                else i.unavailableQty
                                          end) > 0,
                                      'available', 'unavailable')
            where i.id = inventoryId;
        end if;

        -- Check Error
        if inventoryErrorMsg is null then
            insert into `trigger_debug_log` (tableName, triggerName, description, status)
            values ('inventory_lot_line', 'after insert', 'Insert / Update Inventory Table', 'success');
        else
            insert into `trigger_debug_log` (tableName, triggerName, description, errorMessages, status)
            values ('inventory_lot_line', 'after insert', 'Insert / Update Inventory Table', inventoryErrorMsg, 'fail');
        end if;
    end;

    -- clean up
    drop temporary table if exists `temp_inventory`;

    -- Log unhandled errors
    if error_msg is NOT null then
        insert into `trigger_debug_log` (tableName, triggerName, `description`, errorMessages, `status`)
        VALUES ('inventory_lot_line', 'after insert', 'Unhandled error in trigger', error_msg, 'fail');
    end if;
end;