import type { PoolClient } from "pg";

export interface AdjustInventoryParams {
	companyCode: string;
	userId: string;
	itemCode: string;
	whCode: string | null;
	locCode: string | null;
	delta: number;
	transactionType: string;
	remark: string;
	validateStockEnough?: boolean;
}

export async function adjustInventory(
	client: PoolClient,
	params: AdjustInventoryParams,
): Promise<void> {
	const {
		companyCode,
		userId,
		itemCode,
		whCode,
		locCode,
		delta,
		transactionType,
		remark,
		validateStockEnough,
	} = params;

	if (!itemCode || delta === 0) return;

	if (validateStockEnough && delta < 0) {
		const stockRes = await client.query(
			`SELECT COALESCE(CAST(NULLIF(current_qty, '') AS numeric), 0) AS cur
         FROM inventory_stock
        WHERE company_code = $1 AND item_code = $2
          AND COALESCE(warehouse_code, '') = COALESCE($3, '')
          AND COALESCE(location_code, '') = COALESCE($4, '')
        LIMIT 1`,
			[companyCode, itemCode, whCode || "", locCode || ""],
		);
		const cur = parseFloat(stockRes.rows[0]?.cur || "0");
		if (cur + delta < 0) {
			throw new Error(
				`재고 부족: 품목 ${itemCode} (창고 ${whCode || "미지정"}) — 현재 재고 ${cur}, 차감 요청 ${-delta}`,
			);
		}
	}

	const existing = await client.query(
		`SELECT id FROM inventory_stock
      WHERE company_code = $1 AND item_code = $2
        AND COALESCE(warehouse_code, '') = COALESCE($3, '')
        AND COALESCE(location_code, '') = COALESCE($4, '')
      LIMIT 1`,
		[companyCode, itemCode, whCode || "", locCode || ""],
	);

	if (existing.rows.length > 0) {
		if (delta >= 0) {
			await client.query(
				`UPDATE inventory_stock
            SET current_qty = CAST(COALESCE(CAST(NULLIF(current_qty, '') AS numeric), 0) + $1 AS text),
                last_in_date = NOW(),
                updated_date = NOW()
          WHERE id = $2`,
				[delta, existing.rows[0].id],
			);
		} else {
			await client.query(
				`UPDATE inventory_stock
            SET current_qty = CAST(GREATEST(COALESCE(CAST(NULLIF(current_qty, '') AS numeric), 0) + $1, 0) AS text),
                last_out_date = NOW(),
                updated_date = NOW()
          WHERE id = $2`,
				[delta, existing.rows[0].id],
			);
		}
	} else {
		const initQty = Math.max(delta, 0);
		await client.query(
			`INSERT INTO inventory_stock (
        id, company_code, item_code, warehouse_code, location_code,
        current_qty, safety_qty, last_in_date, last_out_date,
        created_date, updated_date, writer
      ) VALUES (
        gen_random_uuid()::text, $1, $2, $3, $4,
        $5, '0',
        ${delta > 0 ? "NOW()" : "NULL"},
        ${delta < 0 ? "NOW()" : "NULL"},
        NOW(), NOW(), $6
      )`,
			[companyCode, itemCode, whCode, locCode, String(initQty), userId],
		);
	}

	const afterRes = await client.query(
		`SELECT current_qty FROM inventory_stock
      WHERE company_code = $1 AND item_code = $2
        AND COALESCE(warehouse_code, '') = COALESCE($3, '')
        AND COALESCE(location_code, '') = COALESCE($4, '')
      LIMIT 1`,
		[companyCode, itemCode, whCode || "", locCode || ""],
	);
	const afterQty = afterRes.rows[0]?.current_qty || "0";

	await client.query(
		`INSERT INTO inventory_history (
      id, company_code, item_code, warehouse_code, location_code,
      transaction_type, transaction_date, quantity, balance_qty, remark,
      writer, created_date
    ) VALUES (
      gen_random_uuid()::text, $1, $2, $3, $4,
      $5, NOW(), $6, $7, $8,
      $9, NOW()
    )`,
		[
			companyCode,
			itemCode,
			whCode,
			locCode,
			transactionType,
			(delta > 0 ? "+" : "") + String(delta),
			afterQty,
			remark,
			userId,
		],
	);
}
