const pool = require("../db/pool");

/**
 * Get list items for a specific household and store
 * @param {number} householdId - Household ID
 * @param {number} storeId - Store ID
 * @param {boolean} includeHistory - Include purchase history
 * @returns {Promise<Array>} List of items
 */
exports.getHouseholdStoreList = async (householdId, storeId, includeHistory = true) => {
  const result = await pool.query(
    `SELECT 
      hl.id,
      i.name AS item_name,
      hl.quantity,
      hl.bought,
      ENCODE(hl.custom_image, 'base64') as item_image,
      hl.custom_image_mime_type as image_mime_type,
      ${includeHistory ? `
        (
          SELECT ARRAY_AGG(added_by_labels.user_label ORDER BY added_by_labels.user_label)
          FROM (
            SELECT DISTINCT
              COALESCE(NULLIF(TRIM(u.display_name), ''), NULLIF(TRIM(u.name), ''), u.username) AS user_label
            FROM household_list_history hlh
            JOIN users u ON hlh.added_by = u.id
            WHERE hlh.household_list_id = hl.id
          ) added_by_labels
        ) as added_by_users,
      ` : 'NULL as added_by_users,'}
      hl.modified_on as last_added_on,
      hic.item_type,
      hic.item_group,
      hic.zone
    FROM household_lists hl
    JOIN items i ON hl.item_id = i.id
    LEFT JOIN household_item_classifications hic 
      ON hl.household_id = hic.household_id 
      AND hl.item_id = hic.item_id
    WHERE hl.household_id = $1 
      AND hl.store_id = $2 
      AND hl.bought = FALSE
    ORDER BY hl.id ASC`,
    [householdId, storeId]
  );
  return result.rows;
};

/**
 * Get a specific item from household list by name
 * @param {number} householdId - Household ID
 * @param {number} storeId - Store ID
 * @param {string} itemName - Item name to search for
 * @returns {Promise<Object|null>} Item or null
 */
exports.getItemByName = async (householdId, storeId, itemName) => {
  // First check if item exists in master catalog
  const itemResult = await pool.query(
    "SELECT id FROM items WHERE name ILIKE $1",
    [itemName]
  );

  if (itemResult.rowCount === 0) {
    return null;
  }

  const itemId = itemResult.rows[0].id;
  const result = await pool.query(
    `SELECT 
      hl.id,
      i.name AS item_name,
      hl.quantity,
      hl.bought,
      ENCODE(hl.custom_image, 'base64') as item_image,
      hl.custom_image_mime_type as image_mime_type,
      (
        SELECT ARRAY_AGG(added_by_labels.user_label ORDER BY added_by_labels.user_label)
        FROM (
          SELECT DISTINCT
            COALESCE(NULLIF(TRIM(u.display_name), ''), NULLIF(TRIM(u.name), ''), u.username) AS user_label
          FROM household_list_history hlh
          JOIN users u ON hlh.added_by = u.id
          WHERE hlh.household_list_id = hl.id
        ) added_by_labels
      ) as added_by_users,
      hl.modified_on as last_added_on,
      hic.item_type,
      hic.item_group,
      hic.zone
    FROM household_lists hl
    JOIN items i ON hl.item_id = i.id
    LEFT JOIN household_item_classifications hic 
      ON hl.household_id = hic.household_id 
      AND hl.item_id = hic.item_id
    WHERE hl.household_id = $1 
      AND hl.store_id = $2 
      AND hl.item_id = $3`,
    [householdId, storeId, itemId]
  );
  return result.rows[0] || null;
};

/**
 * Add or update an item in household list
 * @param {number} householdId - Household ID
 * @param {number} storeId - Store ID
 * @param {string} itemName - Item name
 * @param {number} quantity - Quantity
 * @param {number} userId - User adding the item
 * @param {Buffer|null} imageBuffer - Image buffer
 * @param {string|null} mimeType - MIME type
 * @returns {Promise<number>} List item ID
 */
exports.addOrUpdateItem = async (
  householdId,
  storeId,
  itemName,
  quantity,
  userId,
  imageBuffer = null,
  mimeType = null
) => {
  const lowerItemName = itemName.toLowerCase();

  let itemResult = await pool.query(
    "SELECT id FROM items WHERE name ILIKE $1",
    [lowerItemName]
  );

  let itemId;
  if (itemResult.rowCount === 0) {
    const insertItem = await pool.query(
      "INSERT INTO items (name) VALUES ($1) RETURNING id",
      [lowerItemName]
    );
    itemId = insertItem.rows[0].id;
  } else {
    itemId = itemResult.rows[0].id;
  }

  const listResult = await pool.query(
    `SELECT id, bought FROM household_lists 
     WHERE household_id = $1 
       AND store_id = $2 
       AND item_id = $3`,
    [householdId, storeId, itemId]
  );

  if (listResult.rowCount > 0) {
    const listId = listResult.rows[0].id;
    if (imageBuffer && mimeType) {
      await pool.query(
        `UPDATE household_lists 
         SET quantity = $1, 
             bought = FALSE,
             custom_image = $2,
             custom_image_mime_type = $3,
             modified_on = NOW()
         WHERE id = $4`,
        [quantity, imageBuffer, mimeType, listId]
      );
    } else {
      await pool.query(
        `UPDATE household_lists 
         SET quantity = $1, 
             bought = FALSE,
             modified_on = NOW()
         WHERE id = $2`,
        [quantity, listId]
      );
    }
    return listId;
  } else {
    const insert = await pool.query(
      `INSERT INTO household_lists 
       (household_id, store_id, item_id, quantity, custom_image, custom_image_mime_type) 
       VALUES ($1, $2, $3, $4, $5, $6) 
       RETURNING id`,
      [householdId, storeId, itemId, quantity, imageBuffer, mimeType]
    );
    return insert.rows[0].id;
  }
};

/**
 * Mark item as bought (full or partial)
 * @param {number} listId - List item ID
 * @param {boolean} bought - True to mark as bought, false to unmark
 * @param {number} quantityBought - Optional quantity bought (for partial purchases)
 */
exports.setBought = async (listId, bought, quantityBought = null) => {
  if (bought === false) {
    // Unmarking - just set bought to false
    await pool.query(
      "UPDATE household_lists SET bought = FALSE, modified_on = NOW() WHERE id = $1",
      [listId]
    );
    return;
  }

  // Marking as bought
  if (quantityBought && quantityBought > 0) {
    // Partial purchase - reduce quantity
    const item = await pool.query(
      "SELECT quantity FROM household_lists WHERE id = $1",
      [listId]
    );

    if (!item.rows[0]) return;

    const currentQuantity = item.rows[0].quantity;
    const remainingQuantity = currentQuantity - quantityBought;

    if (remainingQuantity <= 0) {
      // All bought - mark as bought
      await pool.query(
        "UPDATE household_lists SET bought = TRUE, modified_on = NOW() WHERE id = $1",
        [listId]
      );
    } else {
      // Partial - reduce quantity
      await pool.query(
        "UPDATE household_lists SET quantity = $1, modified_on = NOW() WHERE id = $2",
        [remainingQuantity, listId]
      );
    }
  } else {
    // Full purchase - mark as bought
    await pool.query(
      "UPDATE household_lists SET bought = TRUE, modified_on = NOW() WHERE id = $1",
      [listId]
    );
  }
};

/**
 * Add history record for item addition
 * @param {number} listId - List item ID
 * @param {number} quantity - Quantity added
 * @param {number} userId - User who added
 */
exports.addHistoryRecord = async (listId, quantity, userId) => {
  await pool.query(
    `INSERT INTO household_list_history (household_list_id, quantity, added_by, added_on)
     VALUES ($1, $2, $3, NOW())`,
    [listId, quantity, userId]
  );
};

/**
 * Get suggestions for autocomplete
 * @param {string} query - Search query
 * @param {number} householdId - Household ID (for personalized suggestions)
 * @param {number} storeId - Store ID
 * @returns {Promise<Array>} Suggestions
 */
exports.getSuggestions = async (query, householdId, storeId) => {
  // Get items from both master catalog and household history
  const result = await pool.query(
    `SELECT DISTINCT 
       i.name as item_name,
       CASE WHEN hl.id IS NOT NULL THEN 0 ELSE 1 END as sort_order
     FROM items i
     LEFT JOIN household_lists hl 
       ON i.id = hl.item_id 
       AND hl.household_id = $2
       AND hl.store_id = $3
     WHERE i.name ILIKE $1
     ORDER BY sort_order, i.name
     LIMIT 10`,
    [`%${query}%`, householdId, storeId]
  );
  return result.rows;
};

/**
 * Get recently bought items for household/store
 * @param {number} householdId - Household ID
 * @param {number} storeId - Store ID
 * @returns {Promise<Array>} Recently bought items
 */
exports.getRecentlyBoughtItems = async (householdId, storeId) => {
  const result = await pool.query(
    `SELECT 
      hl.id,
      i.name AS item_name,
      hl.quantity,
      hl.bought,
      ENCODE(hl.custom_image, 'base64') as item_image,
      hl.custom_image_mime_type as image_mime_type,
      (
        SELECT ARRAY_AGG(added_by_labels.user_label ORDER BY added_by_labels.user_label)
        FROM (
          SELECT DISTINCT
            COALESCE(NULLIF(TRIM(u.display_name), ''), NULLIF(TRIM(u.name), ''), u.username) AS user_label
          FROM household_list_history hlh
          JOIN users u ON hlh.added_by = u.id
          WHERE hlh.household_list_id = hl.id
        ) added_by_labels
      ) as added_by_users,
      hl.modified_on as last_added_on
    FROM household_lists hl
    JOIN items i ON hl.item_id = i.id
    WHERE hl.household_id = $1 
      AND hl.store_id = $2
      AND hl.bought = TRUE 
      AND hl.modified_on >= NOW() - INTERVAL '24 hours'
    ORDER BY hl.modified_on DESC`,
    [householdId, storeId]
  );
  return result.rows;
};

/**
 * Get classification for household item
 * @param {number} householdId - Household ID
 * @param {number} itemId - Item ID
 * @returns {Promise<Object|null>} Classification or null
 */
exports.getClassification = async (householdId, itemId) => {
  const result = await pool.query(
    `SELECT item_type, item_group, zone, confidence, source
     FROM household_item_classifications
     WHERE household_id = $1 AND item_id = $2`,
    [householdId, itemId]
  );
  return result.rows[0] || null;
};

/**
 * Upsert classification for household item
 * @param {number} householdId - Household ID
 * @param {number} itemId - Item ID
 * @param {Object} classification - Classification data
 * @returns {Promise<Object>} Updated classification
 */
exports.upsertClassification = async (householdId, itemId, classification) => {
  const { item_type, item_group, zone, confidence, source } = classification;

  const result = await pool.query(
    `INSERT INTO household_item_classifications 
     (household_id, item_id, item_type, item_group, zone, confidence, source)
     VALUES ($1, $2, $3, $4, $5, $6, $7)
     ON CONFLICT (household_id, item_id) 
     DO UPDATE SET 
       item_type = EXCLUDED.item_type,
       item_group = EXCLUDED.item_group,
       zone = EXCLUDED.zone,
       confidence = EXCLUDED.confidence,
       source = EXCLUDED.source
     RETURNING *`,
    [householdId, itemId, item_type, item_group, zone, confidence, source]
  );
  return result.rows[0];
};

/**
 * Update list item details
 * @param {number} listId - List item ID
 * @param {string} itemName - New item name (optional)
 * @param {number} quantity - New quantity (optional)
 * @param {string} notes - Notes (optional)
 * @returns {Promise<Object>} Updated item
 */
exports.updateItem = async (listId, itemName, quantity, notes) => {
  // Build dynamic update query
  const updates = [];
  const values = [listId];
  let paramCount = 1;

  if (quantity !== undefined) {
    paramCount++;
    updates.push(`quantity = $${paramCount}`);
    values.push(quantity);
  }

  if (notes !== undefined) {
    paramCount++;
    updates.push(`notes = $${paramCount}`);
    values.push(notes);
  }

  // Always update modified_on
  updates.push(`modified_on = NOW()`);

  if (updates.length === 1) {
    // Only modified_on update
    const result = await pool.query(
      `UPDATE household_lists SET modified_on = NOW() WHERE id = $1 RETURNING *`,
      [listId]
    );
    return result.rows[0];
  }

  const result = await pool.query(
    `UPDATE household_lists SET ${updates.join(', ')} WHERE id = $1 RETURNING *`,
    values
  );

  return result.rows[0];
};

/**
 * Delete a list item
 * @param {number} listId - List item ID
 */
exports.deleteItem = async (listId) => {
  await pool.query("DELETE FROM household_lists WHERE id = $1", [listId]);
};
