-- Migration 00002: Row Level Security (RLS) Policies and Helper Functions

-- 1. Helper Functions
CREATE OR REPLACE FUNCTION public.is_household_member(_household_id UUID)
RETURNS BOOLEAN
LANGUAGE sql
SECURITY DEFINER
SET search_path = public
STABLE
AS $$
  SELECT EXISTS (
    SELECT 1 
    FROM public.household_members
    WHERE household_id = _household_id
      AND user_id = auth.uid()
  );
$$;

CREATE OR REPLACE FUNCTION public.has_household_role(_household_id UUID, _allowed_roles public.household_role[])
RETURNS BOOLEAN
LANGUAGE sql
SECURITY DEFINER
SET search_path = public
STABLE
AS $$
  SELECT EXISTS (
    SELECT 1 
    FROM public.household_members
    WHERE household_id = _household_id
      AND user_id = auth.uid()
      AND role = ANY(_allowed_roles)
  );
$$;

-- Enable RLS on all tables
ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.households ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.household_members ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.categories ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.locations ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.units ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.products ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.inventory_batches ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.stock_movements ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.shopping_lists ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.shopping_list_items ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.purchases ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.purchase_items ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.price_observations ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.budgets ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.inventory_sessions ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.inventory_session_items ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.dietary_preferences ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.recipes ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.meal_plans ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.ai_settings ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.ai_request_logs ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.ai_pending_actions ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.rate_limit_events ENABLE ROW LEVEL SECURITY;

-- 2. Policies for profiles
CREATE POLICY "Users can view all profiles in their households"
    ON public.profiles FOR SELECT
    USING (
        id = auth.uid() OR
        EXISTS (
            SELECT 1 FROM public.household_members m1
            JOIN public.household_members m2 ON m1.household_id = m2.household_id
            WHERE m1.user_id = auth.uid() AND m2.user_id = public.profiles.id
        )
    );

CREATE POLICY "Users can update their own profile"
    ON public.profiles FOR UPDATE
    USING (id = auth.uid())
    WITH CHECK (id = auth.uid());

CREATE POLICY "Users can insert their own profile"
    ON public.profiles FOR INSERT
    WITH CHECK (id = auth.uid());

-- 3. Policies for households
CREATE POLICY "Members can view their households"
    ON public.households FOR SELECT
    USING (public.is_household_member(id));

CREATE POLICY "Authenticated users can create households"
    ON public.households FOR INSERT
    WITH CHECK (owner_id = auth.uid());

CREATE POLICY "OWNER and ADMIN can update household"
    ON public.households FOR UPDATE
    USING (public.has_household_role(id, ARRAY['OWNER', 'ADMIN']::public.household_role[]));

CREATE POLICY "Only OWNER can delete household"
    ON public.households FOR DELETE
    USING (owner_id = auth.uid());

-- 4. Policies for household_members
CREATE POLICY "Members can view household members"
    ON public.household_members FOR SELECT
    USING (public.is_household_member(household_id));

CREATE POLICY "OWNER and ADMIN can add household members"
    ON public.household_members FOR INSERT
    WITH CHECK (public.has_household_role(household_id, ARRAY['OWNER', 'ADMIN']::public.household_role[]));

CREATE POLICY "OWNER and ADMIN can update member roles"
    ON public.household_members FOR UPDATE
    USING (public.has_household_role(household_id, ARRAY['OWNER', 'ADMIN']::public.household_role[]));

CREATE POLICY "OWNER and ADMIN can remove members"
    ON public.household_members FOR DELETE
    USING (public.has_household_role(household_id, ARRAY['OWNER', 'ADMIN']::public.household_role[]) OR user_id = auth.uid());

-- Helper Macro macro-like pattern for tables scoped by household_id
-- Categories, Locations, Units, Products, Inventory Batches, Stock Movements, Shopping Lists, Purchases, Price Observations, Budgets, Inventory Sessions, Dietary Preferences, Recipes, Meal Plans, AI Settings, AI Pending Actions

-- Categories
CREATE POLICY "Members can view categories" ON public.categories FOR SELECT USING (public.is_household_member(household_id));
CREATE POLICY "MEMBER, ADMIN, OWNER can insert categories" ON public.categories FOR INSERT WITH CHECK (public.has_household_role(household_id, ARRAY['MEMBER', 'ADMIN', 'OWNER']::public.household_role[]));
CREATE POLICY "MEMBER, ADMIN, OWNER can update categories" ON public.categories FOR UPDATE USING (public.has_household_role(household_id, ARRAY['MEMBER', 'ADMIN', 'OWNER']::public.household_role[]));
CREATE POLICY "ADMIN and OWNER can delete categories" ON public.categories FOR DELETE USING (public.has_household_role(household_id, ARRAY['ADMIN', 'OWNER']::public.household_role[]));

-- Locations
CREATE POLICY "Members can view locations" ON public.locations FOR SELECT USING (public.is_household_member(household_id));
CREATE POLICY "MEMBER, ADMIN, OWNER can insert locations" ON public.locations FOR INSERT WITH CHECK (public.has_household_role(household_id, ARRAY['MEMBER', 'ADMIN', 'OWNER']::public.household_role[]));
CREATE POLICY "MEMBER, ADMIN, OWNER can update locations" ON public.locations FOR UPDATE USING (public.has_household_role(household_id, ARRAY['MEMBER', 'ADMIN', 'OWNER']::public.household_role[]));
CREATE POLICY "ADMIN and OWNER can delete locations" ON public.locations FOR DELETE USING (public.has_household_role(household_id, ARRAY['ADMIN', 'OWNER']::public.household_role[]));

-- Units
CREATE POLICY "Members can view units" ON public.units FOR SELECT USING (household_id IS NULL OR public.is_household_member(household_id));
CREATE POLICY "MEMBER, ADMIN, OWNER can insert units" ON public.units FOR INSERT WITH CHECK (household_id IS NOT NULL AND public.has_household_role(household_id, ARRAY['MEMBER', 'ADMIN', 'OWNER']::public.household_role[]));
CREATE POLICY "MEMBER, ADMIN, OWNER can update units" ON public.units FOR UPDATE USING (household_id IS NOT NULL AND public.has_household_role(household_id, ARRAY['MEMBER', 'ADMIN', 'OWNER']::public.household_role[]));

-- Products
CREATE POLICY "Members can view products" ON public.products FOR SELECT USING (public.is_household_member(household_id));
CREATE POLICY "MEMBER, ADMIN, OWNER can insert products" ON public.products FOR INSERT WITH CHECK (public.has_household_role(household_id, ARRAY['MEMBER', 'ADMIN', 'OWNER']::public.household_role[]));
CREATE POLICY "MEMBER, ADMIN, OWNER can update products" ON public.products FOR UPDATE USING (public.has_household_role(household_id, ARRAY['MEMBER', 'ADMIN', 'OWNER']::public.household_role[]));
CREATE POLICY "ADMIN and OWNER can delete products" ON public.products FOR DELETE USING (public.has_household_role(household_id, ARRAY['ADMIN', 'OWNER']::public.household_role[]));

-- Inventory Batches
CREATE POLICY "Members can view inventory batches" ON public.inventory_batches FOR SELECT USING (public.is_household_member(household_id));
CREATE POLICY "MEMBER, ADMIN, OWNER can modify inventory batches" ON public.inventory_batches FOR ALL USING (public.has_household_role(household_id, ARRAY['MEMBER', 'ADMIN', 'OWNER']::public.household_role[]));

-- Stock Movements
CREATE POLICY "Members can view stock movements" ON public.stock_movements FOR SELECT USING (public.is_household_member(household_id));
CREATE POLICY "MEMBER, ADMIN, OWNER can insert stock movements" ON public.stock_movements FOR INSERT WITH CHECK (public.has_household_role(household_id, ARRAY['MEMBER', 'ADMIN', 'OWNER']::public.household_role[]));

-- Shopping Lists
CREATE POLICY "Members can view shopping lists" ON public.shopping_lists FOR SELECT USING (public.is_household_member(household_id));
CREATE POLICY "MEMBER, ADMIN, OWNER can modify shopping lists" ON public.shopping_lists FOR ALL USING (public.has_household_role(household_id, ARRAY['MEMBER', 'ADMIN', 'OWNER']::public.household_role[]));

-- Shopping List Items
CREATE POLICY "Members can view shopping list items" ON public.shopping_list_items FOR SELECT USING (
    EXISTS (SELECT 1 FROM public.shopping_lists WHERE id = shopping_list_id AND public.is_household_member(household_id))
);
CREATE POLICY "MEMBER, ADMIN, OWNER can modify shopping list items" ON public.shopping_list_items FOR ALL USING (
    EXISTS (SELECT 1 FROM public.shopping_lists WHERE id = shopping_list_id AND public.has_household_role(household_id, ARRAY['MEMBER', 'ADMIN', 'OWNER']::public.household_role[]))
);

-- Purchases & Purchase Items
CREATE POLICY "Members can view purchases" ON public.purchases FOR SELECT USING (public.is_household_member(household_id));
CREATE POLICY "MEMBER, ADMIN, OWNER can modify purchases" ON public.purchases FOR ALL USING (public.has_household_role(household_id, ARRAY['MEMBER', 'ADMIN', 'OWNER']::public.household_role[]));

CREATE POLICY "Members can view purchase items" ON public.purchase_items FOR SELECT USING (
    EXISTS (SELECT 1 FROM public.purchases WHERE id = purchase_id AND public.is_household_member(household_id))
);
CREATE POLICY "MEMBER, ADMIN, OWNER can modify purchase items" ON public.purchase_items FOR ALL USING (
    EXISTS (SELECT 1 FROM public.purchases WHERE id = purchase_id AND public.has_household_role(household_id, ARRAY['MEMBER', 'ADMIN', 'OWNER']::public.household_role[]))
);

-- Price Observations
CREATE POLICY "Members can view price observations" ON public.price_observations FOR SELECT USING (public.is_household_member(household_id));
CREATE POLICY "MEMBER, ADMIN, OWNER can modify price observations" ON public.price_observations FOR ALL USING (public.has_household_role(household_id, ARRAY['MEMBER', 'ADMIN', 'OWNER']::public.household_role[]));

-- Budgets
CREATE POLICY "Members can view budgets" ON public.budgets FOR SELECT USING (public.is_household_member(household_id));
CREATE POLICY "ADMIN and OWNER can modify budgets" ON public.budgets FOR ALL USING (public.has_household_role(household_id, ARRAY['ADMIN', 'OWNER']::public.household_role[]));

-- Inventory Sessions & Session Items
CREATE POLICY "Members can view inventory sessions" ON public.inventory_sessions FOR SELECT USING (public.is_household_member(household_id));
CREATE POLICY "MEMBER, ADMIN, OWNER can modify inventory sessions" ON public.inventory_sessions FOR ALL USING (public.has_household_role(household_id, ARRAY['MEMBER', 'ADMIN', 'OWNER']::public.household_role[]));

CREATE POLICY "Members can view inventory session items" ON public.inventory_session_items FOR SELECT USING (
    EXISTS (SELECT 1 FROM public.inventory_sessions WHERE id = session_id AND public.is_household_member(household_id))
);
CREATE POLICY "MEMBER, ADMIN, OWNER can modify inventory session items" ON public.inventory_session_items FOR ALL USING (
    EXISTS (SELECT 1 FROM public.inventory_sessions WHERE id = session_id AND public.has_household_role(household_id, ARRAY['MEMBER', 'ADMIN', 'OWNER']::public.household_role[]))
);

-- Dietary Preferences, Recipes, Meal Plans, AI Settings, AI Pending Actions
CREATE POLICY "Members can view dietary preferences" ON public.dietary_preferences FOR SELECT USING (public.is_household_member(household_id));
CREATE POLICY "MEMBER, ADMIN, OWNER can update dietary preferences" ON public.dietary_preferences FOR ALL USING (public.has_household_role(household_id, ARRAY['MEMBER', 'ADMIN', 'OWNER']::public.household_role[]));

CREATE POLICY "Members can view recipes" ON public.recipes FOR SELECT USING (public.is_household_member(household_id));
CREATE POLICY "MEMBER, ADMIN, OWNER can modify recipes" ON public.recipes FOR ALL USING (public.has_household_role(household_id, ARRAY['MEMBER', 'ADMIN', 'OWNER']::public.household_role[]));

CREATE POLICY "Members can view meal plans" ON public.meal_plans FOR SELECT USING (public.is_household_member(household_id));
CREATE POLICY "MEMBER, ADMIN, OWNER can modify meal plans" ON public.meal_plans FOR ALL USING (public.has_household_role(household_id, ARRAY['MEMBER', 'ADMIN', 'OWNER']::public.household_role[]));

CREATE POLICY "Members can view AI settings" ON public.ai_settings FOR SELECT USING (public.is_household_member(household_id));
CREATE POLICY "ADMIN and OWNER can modify AI settings" ON public.ai_settings FOR ALL USING (public.has_household_role(household_id, ARRAY['ADMIN', 'OWNER']::public.household_role[]));

CREATE POLICY "Members can view AI logs" ON public.ai_request_logs FOR SELECT USING (public.is_household_member(household_id));
CREATE POLICY "System can insert AI logs" ON public.ai_request_logs FOR INSERT WITH CHECK (public.is_household_member(household_id));

CREATE POLICY "Members can view pending actions" ON public.ai_pending_actions FOR SELECT USING (public.is_household_member(household_id));
CREATE POLICY "MEMBER, ADMIN, OWNER can modify pending actions" ON public.ai_pending_actions FOR ALL USING (public.has_household_role(household_id, ARRAY['MEMBER', 'ADMIN', 'OWNER']::public.household_role[]));

CREATE POLICY "Users can manage their rate limit events" ON public.rate_limit_events FOR ALL USING (user_id = auth.uid());
