-- Migration: Additional SQL Functions for Inventory Management
-- Week 2: Helper functions for common queries

-- Function: Get inventory items with full details (tags, product info, unit conversion)
CREATE OR REPLACE FUNCTION get_inventory_details()
RETURNS TABLE (
  item_id UUID,
  item_name TEXT,
  quantity DECIMAL,
  unit_abbreviation TEXT,
  unit_name TEXT,
  expiry_date DATE,
  days_until_expiry INTEGER,
  tags TEXT[],
  product_brand TEXT,
  product_image_url TEXT,
  product_barcode TEXT,
  created_at TIMESTAMPTZ,
  updated_at TIMESTAMPTZ
) AS $$
BEGIN
  RETURN QUERY
  SELECT 
    i.id AS item_id,
    i.name AS item_name,
    i.quantity,
    u.abbreviation AS unit_abbreviation,
    u.name AS unit_name,
    i.expiry_date,
    (i.expiry_date - CURRENT_DATE) AS days_until_expiry,
    COALESCE(ARRAY_AGG(DISTINCT t.name) FILTER (WHERE t.name IS NOT NULL), '{}') AS tags,
    p.brand AS product_brand,
    p.image_url AS product_image_url,
    p.barcode AS product_barcode,
    i.created_at,
    i.updated_at
  FROM inventory_items i
    JOIN units u ON i.unit_id = u.id
    LEFT JOIN products p ON i.product_id = p.id
    LEFT JOIN item_tags it ON i.id = it.item_id
    LEFT JOIN tags t ON it.tag_id = t.id
  GROUP BY 
    i.id, i.name, i.quantity, u.abbreviation, u.name, 
    i.expiry_date, p.brand, p.image_url, p.barcode, 
    i.created_at, i.updated_at
  ORDER BY i.created_at DESC;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION get_inventory_details() IS 'Returns all inventory items with denormalized data for display';

-- Function: Get items expiring soon
CREATE OR REPLACE FUNCTION get_expiring_items(days_ahead INTEGER DEFAULT 7)
RETURNS TABLE (
  item_id UUID,
  item_name TEXT,
  quantity DECIMAL,
  unit_abbreviation TEXT,
  expiry_date DATE,
  days_until_expiry INTEGER,
  tags TEXT[]
) AS $$
BEGIN
  RETURN QUERY
  SELECT 
    i.id AS item_id,
    i.name AS item_name,
    i.quantity,
    u.abbreviation AS unit_abbreviation,
    i.expiry_date,
    (i.expiry_date - CURRENT_DATE) AS days_until_expiry,
    COALESCE(ARRAY_AGG(DISTINCT t.name) FILTER (WHERE t.name IS NOT NULL), '{}') AS tags
  FROM inventory_items i
    JOIN units u ON i.unit_id = u.id
    LEFT JOIN item_tags it ON i.id = it.item_id
    LEFT JOIN tags t ON it.tag_id = t.id
  WHERE 
    i.expiry_date IS NOT NULL
    AND i.expiry_date <= CURRENT_DATE + MAKE_INTERVAL(days => days_ahead)
  GROUP BY i.id, i.name, i.quantity, u.abbreviation, i.expiry_date
  ORDER BY i.expiry_date ASC;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION get_expiring_items(INTEGER) IS 'Returns items expiring within specified days (default 7)';

-- Function: Get items by tag
CREATE OR REPLACE FUNCTION get_items_by_tag(tag_name TEXT)
RETURNS TABLE (
  item_id UUID,
  item_name TEXT,
  quantity DECIMAL,
  unit_abbreviation TEXT,
  expiry_date DATE,
  created_at TIMESTAMPTZ
) AS $$
BEGIN
  RETURN QUERY
  SELECT 
    i.id AS item_id,
    i.name AS item_name,
    i.quantity,
    u.abbreviation AS unit_abbreviation,
    i.expiry_date,
    i.created_at
  FROM inventory_items i
    JOIN units u ON i.unit_id = u.id
    JOIN item_tags it ON i.id = it.item_id
    JOIN tags t ON it.tag_id = t.id
  WHERE t.name ILIKE tag_name
  ORDER BY i.created_at DESC;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION get_items_by_tag(TEXT) IS 'Returns all items with specified tag (case-insensitive)';

-- Function: Get low stock items (quantity <= threshold)
CREATE OR REPLACE FUNCTION get_low_stock_items(threshold DECIMAL DEFAULT 1.0)
RETURNS TABLE (
  item_id UUID,
  item_name TEXT,
  quantity DECIMAL,
  unit_abbreviation TEXT,
  tags TEXT[]
) AS $$
BEGIN
  RETURN QUERY
  SELECT 
    i.id AS item_id,
    i.name AS item_name,
    i.quantity,
    u.abbreviation AS unit_abbreviation,
    COALESCE(ARRAY_AGG(DISTINCT t.name) FILTER (WHERE t.name IS NOT NULL), '{}') AS tags
  FROM inventory_items i
    JOIN units u ON i.unit_id = u.id
    LEFT JOIN item_tags it ON i.id = it.item_id
    LEFT JOIN tags t ON it.tag_id = t.id
  WHERE i.quantity <= threshold
  GROUP BY i.id, i.name, i.quantity, u.abbreviation
  ORDER BY i.quantity ASC, i.name ASC;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION get_low_stock_items(DECIMAL) IS 'Returns items with quantity at or below threshold';

-- Function: Update item quantity (consume or restock)
CREATE OR REPLACE FUNCTION update_item_quantity(
  item_uuid UUID,
  quantity_change DECIMAL,
  delete_if_zero BOOLEAN DEFAULT TRUE
)
RETURNS BOOLEAN AS $$
DECLARE
  new_quantity DECIMAL;
BEGIN
  -- Calculate new quantity
  SELECT quantity + quantity_change INTO new_quantity
  FROM inventory_items
  WHERE id = item_uuid;

  IF new_quantity IS NULL THEN
    RETURN FALSE;  -- Item not found
  END IF;

  -- Delete if zero and flag is set
  IF new_quantity <= 0 AND delete_if_zero THEN
    DELETE FROM inventory_items WHERE id = item_uuid;
    RETURN TRUE;
  END IF;

  -- Update quantity (ensure non-negative)
  UPDATE inventory_items
  SET quantity = GREATEST(new_quantity, 0),
      updated_at = NOW()
  WHERE id = item_uuid;

  RETURN TRUE;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION update_item_quantity(UUID, DECIMAL, BOOLEAN) IS 'Updates item quantity (positive for restock, negative for consume). Optionally deletes if zero.';

-- Function: Get inventory statistics
CREATE OR REPLACE FUNCTION get_inventory_stats()
RETURNS TABLE (
  total_items BIGINT,
  total_unique_products BIGINT,
  items_expiring_week BIGINT,
  items_expired BIGINT,
  total_tags_used BIGINT
) AS $$
BEGIN
  RETURN QUERY
  SELECT 
    COUNT(DISTINCT i.id) AS total_items,
    COUNT(DISTINCT i.product_id) FILTER (WHERE i.product_id IS NOT NULL) AS total_unique_products,
    COUNT(i.id) FILTER (
      WHERE i.expiry_date IS NOT NULL 
      AND i.expiry_date BETWEEN CURRENT_DATE AND CURRENT_DATE + INTERVAL '7 days'
    ) AS items_expiring_week,
    COUNT(i.id) FILTER (
      WHERE i.expiry_date IS NOT NULL 
      AND i.expiry_date < CURRENT_DATE
    ) AS items_expired,
    COUNT(DISTINCT it.tag_id) AS total_tags_used
  FROM inventory_items i
    LEFT JOIN item_tags it ON i.id = it.item_id;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION get_inventory_stats() IS 'Returns summary statistics for the entire inventory';

-- Function: Search inventory (full-text search on items and products)
CREATE OR REPLACE FUNCTION search_inventory(search_query TEXT)
RETURNS TABLE (
  item_id UUID,
  item_name TEXT,
  quantity DECIMAL,
  unit_abbreviation TEXT,
  product_brand TEXT,
  tags TEXT[],
  relevance REAL
) AS $$
BEGIN
  RETURN QUERY
  SELECT 
    i.id AS item_id,
    i.name AS item_name,
    i.quantity,
    u.abbreviation AS unit_abbreviation,
    p.brand AS product_brand,
    COALESCE(ARRAY_AGG(DISTINCT t.name) FILTER (WHERE t.name IS NOT NULL), '{}') AS tags,
    ts_rank(
      to_tsvector('english', i.name || ' ' || COALESCE(p.brand, '') || ' ' || COALESCE(p.name, '')),
      plainto_tsquery('english', search_query)
    ) AS relevance
  FROM inventory_items i
    JOIN units u ON i.unit_id = u.id
    LEFT JOIN products p ON i.product_id = p.id
    LEFT JOIN item_tags it ON i.id = it.item_id
    LEFT JOIN tags t ON it.tag_id = t.id
  WHERE 
    to_tsvector('english', i.name || ' ' || COALESCE(p.brand, '') || ' ' || COALESCE(p.name, ''))
    @@ plainto_tsquery('english', search_query)
  GROUP BY i.id, i.name, i.quantity, u.abbreviation, p.brand, p.name
  ORDER BY relevance DESC, i.created_at DESC
  LIMIT 50;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION search_inventory(TEXT) IS 'Full-text search across inventory items and products';
