-- ============================================================================
-- Multi-Household & Multi-Store Architecture Migration
-- ============================================================================
-- This migration transforms the single-list app into a multi-tenant system
-- supporting multiple households, each with multiple stores.
--
-- IMPORTANT: Backup your database before running this migration!
-- pg_dump grocery_list > backup_$(date +%Y%m%d).sql
--
-- Migration Strategy:
-- 1. Create new tables
-- 2. Create "Main Household" for existing users
-- 3. Migrate existing data to new structure
-- 4. Update roles (keep users.role for system admin)
-- 5. Verify data integrity
-- 6. (Manual step) Drop old tables after verification
-- ============================================================================

BEGIN;

-- ============================================================================
-- STEP 1: CREATE NEW TABLES
-- ============================================================================

-- Households table
CREATE TABLE IF NOT EXISTS households (
  id SERIAL PRIMARY KEY,
  name VARCHAR(100) NOT NULL,
  created_at TIMESTAMP DEFAULT NOW(),
  created_by INTEGER REFERENCES users(id) ON DELETE SET NULL,
  invite_code VARCHAR(20) UNIQUE NOT NULL,
  code_expires_at TIMESTAMP
);

CREATE INDEX idx_households_invite_code ON households(invite_code);
COMMENT ON TABLE households IS 'Household groups (families, roommates, etc.)';
COMMENT ON COLUMN households.invite_code IS 'Unique code for inviting users to join household';

-- Store types table
CREATE TABLE IF NOT EXISTS stores (
  id SERIAL PRIMARY KEY,
  name VARCHAR(50) NOT NULL UNIQUE,
  default_zones JSONB,
  created_at TIMESTAMP DEFAULT NOW()
);

COMMENT ON TABLE stores IS 'Store types/chains (Costco, Target, Walmart, etc.)';
COMMENT ON COLUMN stores.default_zones IS 'JSON array of default zone names for this store type';

-- User-Household membership with per-household roles
CREATE TABLE IF NOT EXISTS household_members (
  id SERIAL PRIMARY KEY,
  household_id INTEGER REFERENCES households(id) ON DELETE CASCADE,
  user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
  role VARCHAR(20) NOT NULL CHECK (role IN ('admin', 'user')),
  joined_at TIMESTAMP DEFAULT NOW(),
  UNIQUE(household_id, user_id)
);

CREATE INDEX idx_household_members_user ON household_members(user_id);
CREATE INDEX idx_household_members_household ON household_members(household_id);
COMMENT ON TABLE household_members IS 'User membership in households with per-household roles';
COMMENT ON COLUMN household_members.role IS 'admin: full control, user: standard member';

-- Household-Store relationship
CREATE TABLE IF NOT EXISTS household_stores (
  id SERIAL PRIMARY KEY,
  household_id INTEGER REFERENCES households(id) ON DELETE CASCADE,
  store_id INTEGER REFERENCES stores(id) ON DELETE CASCADE,
  is_default BOOLEAN DEFAULT FALSE,
  added_at TIMESTAMP DEFAULT NOW(),
  UNIQUE(household_id, store_id)
);

CREATE INDEX idx_household_stores_household ON household_stores(household_id);
COMMENT ON TABLE household_stores IS 'Which stores each household shops at';

-- Master item catalog (shared across all households)
CREATE TABLE IF NOT EXISTS items (
  id SERIAL PRIMARY KEY,
  name VARCHAR(255) NOT NULL UNIQUE,
  default_image BYTEA,
  default_image_mime_type VARCHAR(50),
  created_at TIMESTAMP DEFAULT NOW(),
  usage_count INTEGER DEFAULT 0
);

CREATE INDEX idx_items_name ON items(name);
CREATE INDEX idx_items_usage_count ON items(usage_count DESC);
COMMENT ON TABLE items IS 'Master item catalog shared across all households';
COMMENT ON COLUMN items.usage_count IS 'Popularity metric for suggestions';

-- Household-specific grocery lists (per store)
CREATE TABLE IF NOT EXISTS household_lists (
  id SERIAL PRIMARY KEY,
  household_id INTEGER REFERENCES households(id) ON DELETE CASCADE,
  store_id INTEGER REFERENCES stores(id) ON DELETE CASCADE,
  item_id INTEGER REFERENCES items(id) ON DELETE CASCADE,
  quantity INTEGER NOT NULL DEFAULT 1,
  bought BOOLEAN DEFAULT FALSE,
  custom_image BYTEA,
  custom_image_mime_type VARCHAR(50),
  added_by INTEGER REFERENCES users(id) ON DELETE SET NULL,
  modified_on TIMESTAMP DEFAULT NOW(),
  UNIQUE(household_id, store_id, item_id)
);

CREATE INDEX idx_household_lists_household_store ON household_lists(household_id, store_id);
CREATE INDEX idx_household_lists_bought ON household_lists(household_id, store_id, bought);
CREATE INDEX idx_household_lists_modified ON household_lists(modified_on DESC);
COMMENT ON TABLE household_lists IS 'Grocery lists scoped to household + store combination';

-- Household-specific item classifications (per store)
CREATE TABLE IF NOT EXISTS household_item_classifications (
  id SERIAL PRIMARY KEY,
  household_id INTEGER REFERENCES households(id) ON DELETE CASCADE,
  store_id INTEGER REFERENCES stores(id) ON DELETE CASCADE,
  item_id INTEGER REFERENCES items(id) ON DELETE CASCADE,
  item_type VARCHAR(50),
  item_group VARCHAR(100),
  zone VARCHAR(100),
  confidence DECIMAL(3,2) DEFAULT 1.0 CHECK (confidence >= 0 AND confidence <= 1),
  source VARCHAR(20) DEFAULT 'user' CHECK (source IN ('user', 'ml', 'default')),
  created_at TIMESTAMP DEFAULT NOW(),
  updated_at TIMESTAMP DEFAULT NOW(),
  UNIQUE(household_id, store_id, item_id)
);

CREATE INDEX idx_household_classifications ON household_item_classifications(household_id, store_id);
CREATE INDEX idx_household_classifications_type ON household_item_classifications(item_type);
CREATE INDEX idx_household_classifications_zone ON household_item_classifications(zone);
COMMENT ON TABLE household_item_classifications IS 'Item classifications scoped to household + store';

-- History tracking
CREATE TABLE IF NOT EXISTS household_list_history (
  id SERIAL PRIMARY KEY,
  household_list_id INTEGER REFERENCES household_lists(id) ON DELETE CASCADE,
  quantity INTEGER NOT NULL,
  added_by INTEGER REFERENCES users(id) ON DELETE SET NULL,
  added_on TIMESTAMP DEFAULT NOW()
);

CREATE INDEX idx_household_history_list ON household_list_history(household_list_id);
CREATE INDEX idx_household_history_user ON household_list_history(added_by);
CREATE INDEX idx_household_history_date ON household_list_history(added_on DESC);
COMMENT ON TABLE household_list_history IS 'Tracks who added items and when';

-- ============================================================================
-- STEP 2: CREATE DEFAULT HOUSEHOLD AND STORE
-- ============================================================================

-- Create default household for existing users
INSERT INTO households (name, created_by, invite_code)
SELECT 
  'Main Household',
  (SELECT id FROM users WHERE role = 'admin' LIMIT 1), -- First admin as creator
  'MAIN' || LPAD(FLOOR(RANDOM() * 1000000)::TEXT, 6, '0') -- Random 6-digit code
WHERE NOT EXISTS (SELECT 1 FROM households WHERE name = 'Main Household');

-- Create default Costco store
INSERT INTO stores (name, default_zones)
VALUES (
  'Costco',
  '{
    "zones": [
      "Entrance & Seasonal",
      "Fresh Produce",
      "Meat & Seafood",
      "Dairy & Refrigerated",
      "Deli & Prepared Foods",
      "Bakery & Bread",
      "Frozen Foods",
      "Beverages",
      "Snacks & Candy",
      "Pantry & Dry Goods",
      "Health & Beauty",
      "Household & Cleaning",
      "Other"
    ]
  }'::jsonb
)
ON CONFLICT (name) DO NOTHING;

-- Link default household to default store
INSERT INTO household_stores (household_id, store_id, is_default)
SELECT 
  (SELECT id FROM households WHERE name = 'Main Household'),
  (SELECT id FROM stores WHERE name = 'Costco'),
  TRUE
WHERE NOT EXISTS (
  SELECT 1 FROM household_stores 
  WHERE household_id = (SELECT id FROM households WHERE name = 'Main Household')
);

-- ============================================================================
-- STEP 3: MIGRATE USERS TO HOUSEHOLD MEMBERS
-- ============================================================================

-- Add all existing users to Main Household
-- Old admins become household admins, others become standard users
INSERT INTO household_members (household_id, user_id, role)
SELECT 
  (SELECT id FROM households WHERE name = 'Main Household'),
  id,
  CASE 
    WHEN role = 'admin' THEN 'admin'
    ELSE 'user'
  END
FROM users
WHERE NOT EXISTS (
  SELECT 1 FROM household_members hm 
  WHERE hm.user_id = users.id 
  AND hm.household_id = (SELECT id FROM households WHERE name = 'Main Household')
);

-- ============================================================================
-- STEP 4: MIGRATE ITEMS TO MASTER CATALOG
-- ============================================================================

-- Extract unique items from grocery_list into master items table
INSERT INTO items (name, default_image, default_image_mime_type, created_at, usage_count)
SELECT 
  LOWER(TRIM(item_name)) as name,
  item_image,
  image_mime_type,
  MIN(modified_on) as created_at,
  COUNT(*) as usage_count
FROM grocery_list
WHERE NOT EXISTS (
  SELECT 1 FROM items WHERE LOWER(items.name) = LOWER(TRIM(grocery_list.item_name))
)
GROUP BY LOWER(TRIM(item_name)), item_image, image_mime_type
ON CONFLICT (name) DO NOTHING;

-- ============================================================================
-- STEP 5: MIGRATE GROCERY_LIST TO HOUSEHOLD_LISTS
-- ============================================================================

-- Migrate current list to household_lists
INSERT INTO household_lists (
  household_id, 
  store_id, 
  item_id, 
  quantity, 
  bought, 
  custom_image,
  custom_image_mime_type,
  added_by, 
  modified_on
)
SELECT 
  (SELECT id FROM households WHERE name = 'Main Household'),
  (SELECT id FROM stores WHERE name = 'Costco'),
  i.id,
  gl.quantity,
  gl.bought,
  CASE WHEN gl.item_image != i.default_image THEN gl.item_image ELSE NULL END, -- Only store if different
  CASE WHEN gl.item_image != i.default_image THEN gl.image_mime_type ELSE NULL END,
  gl.added_by,
  gl.modified_on
FROM grocery_list gl
JOIN items i ON LOWER(i.name) = LOWER(TRIM(gl.item_name))
WHERE NOT EXISTS (
  SELECT 1 FROM household_lists hl
  WHERE hl.household_id = (SELECT id FROM households WHERE name = 'Main Household')
  AND hl.store_id = (SELECT id FROM stores WHERE name = 'Costco')
  AND hl.item_id = i.id
)
ON CONFLICT (household_id, store_id, item_id) DO NOTHING;

-- ============================================================================
-- STEP 6: MIGRATE ITEM_CLASSIFICATION TO HOUSEHOLD_ITEM_CLASSIFICATIONS
-- ============================================================================

-- Migrate classifications
INSERT INTO household_item_classifications (
  household_id,
  store_id,
  item_id,
  item_type,
  item_group,
  zone,
  confidence,
  source,
  created_at,
  updated_at
)
SELECT 
  (SELECT id FROM households WHERE name = 'Main Household'),
  (SELECT id FROM stores WHERE name = 'Costco'),
  i.id,
  ic.item_type,
  ic.item_group,
  ic.zone,
  ic.confidence,
  ic.source,
  ic.created_at,
  ic.updated_at
FROM item_classification ic
JOIN grocery_list gl ON ic.id = gl.id
JOIN items i ON LOWER(i.name) = LOWER(TRIM(gl.item_name))
WHERE NOT EXISTS (
  SELECT 1 FROM household_item_classifications hic
  WHERE hic.household_id = (SELECT id FROM households WHERE name = 'Main Household')
  AND hic.store_id = (SELECT id FROM stores WHERE name = 'Costco')
  AND hic.item_id = i.id
)
ON CONFLICT (household_id, store_id, item_id) DO NOTHING;

-- ============================================================================
-- STEP 7: MIGRATE GROCERY_HISTORY TO HOUSEHOLD_LIST_HISTORY
-- ============================================================================

-- Migrate history records
INSERT INTO household_list_history (household_list_id, quantity, added_by, added_on)
SELECT 
  hl.id,
  gh.quantity,
  gh.added_by,
  gh.added_on
FROM grocery_history gh
JOIN grocery_list gl ON gh.list_item_id = gl.id
JOIN items i ON LOWER(i.name) = LOWER(TRIM(gl.item_name))
JOIN household_lists hl ON hl.item_id = i.id 
  AND hl.household_id = (SELECT id FROM households WHERE name = 'Main Household')
  AND hl.store_id = (SELECT id FROM stores WHERE name = 'Costco')
WHERE NOT EXISTS (
  SELECT 1 FROM household_list_history hlh
  WHERE hlh.household_list_id = hl.id
  AND hlh.added_by = gh.added_by
  AND hlh.added_on = gh.added_on
);

-- ============================================================================
-- STEP 8: UPDATE USER ROLES (SYSTEM-WIDE)
-- ============================================================================

-- Update system roles: admin → system_admin, others → user
UPDATE users 
SET role = 'system_admin' 
WHERE role = 'admin';

UPDATE users 
SET role = 'user' 
WHERE role IN ('editor', 'viewer');

-- ============================================================================
-- VERIFICATION QUERIES
-- ============================================================================

-- Run these to verify migration success:

-- Check household created
-- SELECT * FROM households;

-- Check all users added to household
-- SELECT u.username, u.role as system_role, hm.role as household_role
-- FROM users u
-- JOIN household_members hm ON u.id = hm.user_id
-- ORDER BY u.id;

-- Check items migrated
-- SELECT COUNT(*) as total_items FROM items;
-- SELECT COUNT(*) as original_items FROM (SELECT DISTINCT item_name FROM grocery_list) sub;

-- Check lists migrated
-- SELECT COUNT(*) as new_lists FROM household_lists;
-- SELECT COUNT(*) as old_lists FROM grocery_list;

-- Check classifications migrated
-- SELECT COUNT(*) as new_classifications FROM household_item_classifications;
-- SELECT COUNT(*) as old_classifications FROM item_classification;

-- Check history migrated
-- SELECT COUNT(*) as new_history FROM household_list_history;
-- SELECT COUNT(*) as old_history FROM grocery_history;

-- ============================================================================
-- MANUAL STEPS AFTER VERIFICATION
-- ============================================================================

-- After verifying data integrity, uncomment and run these to clean up:

-- DROP TABLE IF EXISTS grocery_history CASCADE;
-- DROP TABLE IF EXISTS item_classification CASCADE;
-- DROP TABLE IF EXISTS grocery_list CASCADE;

COMMIT;

-- ============================================================================
-- ROLLBACK (if something goes wrong)
-- ============================================================================

-- ROLLBACK;

-- Then restore from backup:
-- psql -U your_user -d grocery_list < backup_YYYYMMDD.sql
