-- Migration: Initial database schema
-- Created: 2026-02-09
-- Issue: #13
-- Description: Creates core tables for Pantry app (inventory, products, tags, units)

-- ======================
-- ENUM TYPES
-- ======================

CREATE TYPE tag_category AS ENUM (
  'position',    -- Location: fridge, freezer, pantry
  'type',        -- Food type: dairy, meat, vegan
  'dietary',     -- Diet: gluten-free, vegan, organic
  'custom'       -- User-defined
);

CREATE TYPE unit_type AS ENUM (
  'weight',   -- kg, g, lb, oz
  'volume',   -- L, mL, cup, tbsp
  'count',    -- pcs, items (no conversion)
  'custom'    -- can, jar, bottle (user-defined)
);

-- ======================
-- BASE TABLES (no foreign keys)
-- ======================

-- Units: measurement units with conversion support
CREATE TABLE units (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  
  -- Core data
  name TEXT NOT NULL,           -- "kilogram", "liter", "piece"
  abbreviation TEXT NOT NULL,   -- "kg", "L", "pcs"
  unit_type unit_type NOT NULL,
  
  -- Conversion system
  base_unit_id UUID REFERENCES units(id),  -- NULL = this is a base unit
  conversion_factor DECIMAL(20,10),        -- Factor to convert to base unit
  
  -- Metadata
  is_default BOOLEAN DEFAULT false,  -- Shipped with app
  created_by UUID REFERENCES auth.users(id),  -- NULL = system unit
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  
  CONSTRAINT unique_unit_abbr UNIQUE (abbreviation, created_by),
  CONSTRAINT check_conversion_logic CHECK (
    (base_unit_id IS NULL AND conversion_factor IS NULL) OR 
    (base_unit_id IS NOT NULL AND conversion_factor IS NOT NULL)
  )
);

-- Tags: flexible labeling system
CREATE TABLE tags (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  
  -- Core data
  name TEXT NOT NULL,
  category tag_category NOT NULL DEFAULT 'custom',
  
  -- Visual
  icon TEXT,    -- Emoji or icon name: "🧊", "cheese"
  color TEXT,   -- Hex color: "#3b82f6"
  
  -- Ownership
  created_by UUID REFERENCES auth.users(id),  -- NULL = system tag
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  
  CONSTRAINT unique_tag_name UNIQUE (name, created_by)
);

-- ======================
-- MAIN TABLES
-- ======================

-- Products: cached product data from Open Food Facts
CREATE TABLE products (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  
  -- Open Food Facts data
  barcode TEXT UNIQUE NOT NULL,
  name TEXT NOT NULL,
  brand TEXT,
  image_url TEXT,
  image_small_url TEXT,  -- Thumbnail
  
  -- Categories from Open Food Facts
  categories TEXT[],  -- Array: ['dairy', 'milk']
  
  -- Nutrition (optional, for future features)
  nutrition JSONB,  -- Full nutrition data
  
  -- Defaults
  default_unit_id UUID REFERENCES units(id),
  default_quantity DECIMAL(10,2),  -- E.g., 1L bottle
  
  -- Metadata
  source TEXT DEFAULT 'openfoodfacts',
  cached_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  last_fetched TIMESTAMPTZ,
  
  -- Quality score (from Open Food Facts)
  completeness_score INTEGER CHECK (completeness_score BETWEEN 0 AND 100)
);

-- Inventory Items: actual items in your kitchen right now
CREATE TABLE inventory_items (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  
  -- Product reference (nullable for custom items)
  product_id UUID REFERENCES products(id) ON DELETE SET NULL,
  
  -- Core data
  name TEXT NOT NULL,  -- Product name or custom name
  quantity DECIMAL(10,2) NOT NULL CHECK (quantity >= 0),
  unit_id UUID NOT NULL REFERENCES units(id),
  
  -- Optional metadata
  expiry_date DATE,
  location TEXT,  -- Free text: "top shelf", "door", etc.
  notes TEXT,
  
  -- Audit trail
  added_by UUID NOT NULL REFERENCES auth.users(id),
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Item Tags: many-to-many relationship between items and tags
CREATE TABLE item_tags (
  item_id UUID NOT NULL REFERENCES inventory_items(id) ON DELETE CASCADE,
  tag_id UUID NOT NULL REFERENCES tags(id) ON DELETE CASCADE,
  
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  
  PRIMARY KEY (item_id, tag_id)
);

-- User Profiles: additional user metadata
CREATE TABLE user_profiles (
  id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
  
  display_name TEXT,
  avatar_url TEXT,
  
  -- Preferences
  default_unit_system TEXT DEFAULT 'metric',  -- 'metric' or 'imperial'
  theme TEXT DEFAULT 'auto',                  -- 'light', 'dark', 'auto'
  
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- ======================
-- INDEXES
-- ======================

-- Units
CREATE INDEX idx_units_type ON units(unit_type);
CREATE INDEX idx_units_base ON units(base_unit_id);

-- Tags
CREATE INDEX idx_tags_category ON tags(category);
CREATE INDEX idx_tags_created_by ON tags(created_by);

-- Products
CREATE UNIQUE INDEX idx_products_barcode ON products(barcode);
CREATE INDEX idx_products_name ON products USING GIN (to_tsvector('english', name));
CREATE INDEX idx_products_search ON products 
  USING GIN (to_tsvector('english', name || ' ' || COALESCE(brand, '')));

-- Inventory Items
CREATE INDEX idx_items_product ON inventory_items(product_id);
CREATE INDEX idx_items_added_by ON inventory_items(added_by);
CREATE INDEX idx_items_expiry ON inventory_items(expiry_date) WHERE expiry_date IS NOT NULL;

-- Item Tags
CREATE INDEX idx_item_tags_tag ON item_tags(tag_id);
CREATE INDEX idx_item_tags_item ON item_tags(item_id);

-- ======================
-- FUNCTIONS
-- ======================

-- Auto-update timestamp trigger function
CREATE OR REPLACE FUNCTION update_updated_at()
RETURNS TRIGGER AS $$
BEGIN
  NEW.updated_at = NOW();
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- Unit conversion function
CREATE OR REPLACE FUNCTION convert_unit(
  quantity DECIMAL,
  from_unit_id UUID,
  to_unit_id UUID
)
RETURNS DECIMAL AS $$
DECLARE
  from_factor DECIMAL;
  to_factor DECIMAL;
  from_type unit_type;
  to_type unit_type;
  base_quantity DECIMAL;
BEGIN
  -- Get unit types and conversion factors
  SELECT unit_type, 
         COALESCE(conversion_factor, 1.0) INTO from_type, from_factor
  FROM units WHERE id = from_unit_id;
  
  SELECT unit_type,
         COALESCE(conversion_factor, 1.0) INTO to_type, to_factor
  FROM units WHERE id = to_unit_id;
  
  -- Check if units are compatible
  IF from_type != to_type THEN
    RAISE EXCEPTION 'Cannot convert between % and %', from_type, to_type;
  END IF;
  
  -- Convert to base unit, then to target unit
  base_quantity := quantity * from_factor;
  RETURN base_quantity / to_factor;
END;
$$ LANGUAGE plpgsql IMMUTABLE;

-- Full-text search function for products
CREATE OR REPLACE FUNCTION search_products(search_query TEXT)
RETURNS TABLE (
  id UUID,
  barcode TEXT,
  name TEXT,
  brand TEXT,
  rank REAL
) AS $$
BEGIN
  RETURN QUERY
  SELECT 
    p.id,
    p.barcode,
    p.name,
    p.brand,
    ts_rank(to_tsvector('english', p.name || ' ' || COALESCE(p.brand, '')), 
            plainto_tsquery('english', search_query)) AS rank
  FROM products p
  WHERE to_tsvector('english', p.name || ' ' || COALESCE(p.brand, '')) 
        @@ plainto_tsquery('english', search_query)
  ORDER BY rank DESC
  LIMIT 20;
END;
$$ LANGUAGE plpgsql;

-- ======================
-- TRIGGERS
-- ======================

-- Auto-update timestamp triggers
CREATE TRIGGER update_items_updated_at
  BEFORE UPDATE ON inventory_items
  FOR EACH ROW
  EXECUTE FUNCTION update_updated_at();

CREATE TRIGGER update_profiles_updated_at
  BEFORE UPDATE ON user_profiles
  FOR EACH ROW
  EXECUTE FUNCTION update_updated_at();

-- ======================
-- COMMENTS
-- ======================

COMMENT ON TABLE inventory_items IS 'Current inventory items in the kitchen';
COMMENT ON TABLE products IS 'Cached product data from Open Food Facts';
COMMENT ON TABLE tags IS 'Flexible labeling system for organization';
COMMENT ON TABLE item_tags IS 'Many-to-many relationship between items and tags';
COMMENT ON TABLE units IS 'Measurement units with conversion support';
COMMENT ON TABLE user_profiles IS 'Additional user metadata and preferences';

COMMENT ON FUNCTION update_updated_at() IS 'Automatically updates the updated_at timestamp';
COMMENT ON FUNCTION convert_unit(DECIMAL, UUID, UUID) IS 'Converts quantity between compatible units';
COMMENT ON FUNCTION search_products(TEXT) IS 'Full-text search for products by name and brand';
