-- Migration 00003: Transactional Stock Adjustment RPC (adjust_product_stock with FEFO)

CREATE OR REPLACE FUNCTION public.adjust_product_stock(
    p_household_id UUID,
    p_product_id UUID,
    p_quantity_change NUMERIC,
    p_reason public.stock_movement_reason,
    p_batch_id UUID DEFAULT NULL,
    p_note TEXT DEFAULT NULL
)
RETURNS NUMERIC
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
DECLARE
    v_user_id UUID;
    v_total_before NUMERIC := 0.0;
    v_total_after NUMERIC := 0.0;
    v_target_batch RECORD;
    v_remaining_to_deduct NUMERIC;
    v_deduct_amount NUMERIC;
BEGIN
    v_user_id := auth.uid();

    -- 1. Check permissions
    IF NOT public.has_household_role(p_household_id, ARRAY['MEMBER', 'ADMIN', 'OWNER']::public.household_role[]) THEN
        RAISE EXCEPTION 'PERMISSION_DENIED: User is not authorized to modify stock in household %', p_household_id;
    END IF;

    -- 2. Lock product and calculate current total stock
    PERFORM 1 FROM public.products WHERE id = p_product_id AND household_id = p_household_id FOR UPDATE;
    
    SELECT COALESCE(SUM(quantity), 0.0) INTO v_total_before
    FROM public.inventory_batches
    WHERE household_id = p_household_id AND product_id = p_product_id;

    -- 3. Check for negative stock
    IF (v_total_before + p_quantity_change) < 0 THEN
        RAISE EXCEPTION 'INSUFFICIENT_STOCK: Required quantity reduction exceeds current total stock (%)', v_total_before;
    END IF;

    -- 4. Apply changes
    IF p_batch_id IS NOT NULL THEN
        -- Target specific batch
        SELECT * INTO v_target_batch
        FROM public.inventory_batches
        WHERE id = p_batch_id AND product_id = p_product_id AND household_id = p_household_id
        FOR UPDATE;

        IF NOT FOUND THEN
            RAISE EXCEPTION 'BATCH_NOT_FOUND: Specified batch % does not exist', p_batch_id;
        END IF;

        IF (v_target_batch.quantity + p_quantity_change) < 0 THEN
            RAISE EXCEPTION 'INSUFFICIENT_BATCH_STOCK: Batch quantity cannot be reduced below 0';
        END IF;

        UPDATE public.inventory_batches
        SET quantity = quantity + p_quantity_change,
            updated_at = NOW()
        WHERE id = p_batch_id;

    ELSE
        -- No explicit batch provided
        IF p_quantity_change > 0 THEN
            -- Increase stock: Add to default batch (batch without expiration_date or newest) or create new batch
            SELECT id INTO p_batch_id
            FROM public.inventory_batches
            WHERE household_id = p_household_id 
              AND product_id = p_product_id
              AND expiration_date IS NULL
            ORDER BY created_at DESC
            LIMIT 1;

            IF p_batch_id IS NOT NULL THEN
                UPDATE public.inventory_batches
                SET quantity = quantity + p_quantity_change,
                    updated_at = NOW()
                WHERE id = p_batch_id;
            ELSE
                INSERT INTO public.inventory_batches (household_id, product_id, quantity)
                VALUES (p_household_id, p_product_id, p_quantity_change)
                RETURNING id INTO p_batch_id;
            END IF;

        ELSIF p_quantity_change < 0 THEN
            -- FEFO Deduction (First Expire, First Out)
            v_remaining_to_deduct := ABS(p_quantity_change);

            FOR v_target_batch IN
                SELECT id, quantity
                FROM public.inventory_batches
                WHERE household_id = p_household_id
                  AND product_id = p_product_id
                  AND quantity > 0
                ORDER BY 
                  expiration_date ASC NULLS LAST,
                  created_at ASC
                FOR UPDATE
            LOOP
                IF v_remaining_to_deduct <= 0 THEN
                    EXIT;
                END IF;

                v_deduct_amount := LEAST(v_target_batch.quantity, v_remaining_to_deduct);

                UPDATE public.inventory_batches
                SET quantity = quantity - v_deduct_amount,
                    updated_at = NOW()
                WHERE id = v_target_batch.id;

                v_remaining_to_deduct := v_remaining_to_deduct - v_deduct_amount;
            END LOOP;
        END IF;
    END IF;

    -- 5. Calculate new total stock
    SELECT COALESCE(SUM(quantity), 0.0) INTO v_total_after
    FROM public.inventory_batches
    WHERE household_id = p_household_id AND product_id = p_product_id;

    -- 6. Insert stock_movements record
    INSERT INTO public.stock_movements (
        household_id,
        product_id,
        batch_id,
        quantity_before,
        quantity_change,
        quantity_after,
        reason,
        note,
        created_by
    ) VALUES (
        p_household_id,
        p_product_id,
        p_batch_id,
        v_total_before,
        p_quantity_change,
        v_total_after,
        p_reason,
        p_note,
        v_user_id
    );

    RETURN v_total_after;
END;
$$;
