-- Monaco USA Portal 2026 - Initial Database Schema
-- Run this migration to set up all tables, views, triggers, and RLS policies

-- ============================================
-- MEMBERSHIP STATUSES (Admin-configurable)
-- ============================================
CREATE TABLE public.membership_statuses (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  name TEXT NOT NULL UNIQUE,
  display_name TEXT NOT NULL,
  color TEXT NOT NULL DEFAULT '#6b7280',
  description TEXT,
  is_default BOOLEAN DEFAULT FALSE,
  sort_order INTEGER DEFAULT 0,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- Default statuses
INSERT INTO public.membership_statuses (name, display_name, color, description, is_default, sort_order) VALUES
  ('pending', 'Pending', '#eab308', 'New member, awaiting dues payment', true, 1),
  ('active', 'Active', '#22c55e', 'Dues paid, full access', false, 2),
  ('inactive', 'Inactive', '#6b7280', 'Lapsed membership or suspended', false, 3),
  ('expired', 'Expired', '#ef4444', 'Membership terminated', false, 4);

-- ============================================
-- MEMBERSHIP TYPES (Admin-configurable pricing)
-- ============================================
CREATE TABLE public.membership_types (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  name TEXT NOT NULL UNIQUE,
  display_name TEXT NOT NULL,
  annual_dues DECIMAL(10,2) NOT NULL,
  description TEXT,
  is_default BOOLEAN DEFAULT FALSE,
  is_active BOOLEAN DEFAULT TRUE,
  sort_order INTEGER DEFAULT 0,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- Default membership types
INSERT INTO public.membership_types (name, display_name, annual_dues, description, is_default, sort_order) VALUES
  ('regular', 'Regular Member', 50.00, 'Standard individual membership', true, 1),
  ('student', 'Student', 25.00, 'For students with valid ID', false, 2),
  ('senior', 'Senior (65+)', 35.00, 'For members 65 years and older', false, 3),
  ('family', 'Family', 75.00, 'Household membership', false, 4),
  ('honorary', 'Honorary Member', 0.00, 'Granted by the board', false, 5);

-- ============================================
-- MEMBERS TABLE
-- ============================================
CREATE TABLE public.members (
  id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
  member_id TEXT UNIQUE NOT NULL,

  -- Personal Info
  first_name TEXT NOT NULL,
  last_name TEXT NOT NULL,
  email TEXT UNIQUE NOT NULL,
  phone TEXT NOT NULL,
  date_of_birth DATE NOT NULL,
  address TEXT NOT NULL,
  nationality TEXT[] NOT NULL DEFAULT '{}',

  -- Membership
  role TEXT NOT NULL DEFAULT 'member' CHECK (role IN ('member', 'board', 'admin')),
  membership_status_id UUID REFERENCES public.membership_statuses(id),
  membership_type_id UUID REFERENCES public.membership_types(id),
  member_since DATE DEFAULT CURRENT_DATE,

  -- Profile
  avatar_url TEXT,

  -- Admin
  notes TEXT,

  -- Timestamps
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

-- Auto-generate member_id trigger
CREATE OR REPLACE FUNCTION generate_member_id()
RETURNS TRIGGER AS $$
DECLARE
  next_num INTEGER;
BEGIN
  SELECT COALESCE(MAX(CAST(SUBSTRING(member_id FROM 6) AS INTEGER)), 0) + 1
  INTO next_num
  FROM public.members;

  NEW.member_id := 'MUSA-' || LPAD(next_num::TEXT, 4, '0');
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER set_member_id
  BEFORE INSERT ON public.members
  FOR EACH ROW
  WHEN (NEW.member_id IS NULL)
  EXECUTE FUNCTION generate_member_id();

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

CREATE TRIGGER members_updated_at
  BEFORE UPDATE ON public.members
  FOR EACH ROW
  EXECUTE FUNCTION update_updated_at();

-- ============================================
-- DUES PAYMENTS
-- ============================================
CREATE TABLE public.dues_payments (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  member_id UUID NOT NULL REFERENCES public.members(id) ON DELETE CASCADE,

  amount DECIMAL(10,2) NOT NULL,
  currency TEXT DEFAULT 'EUR',
  payment_date DATE NOT NULL,
  due_date DATE NOT NULL,
  payment_method TEXT DEFAULT 'bank_transfer',
  reference TEXT,
  notes TEXT,

  recorded_by UUID NOT NULL REFERENCES public.members(id),
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- Auto-calculate due_date (1 year from payment)
CREATE OR REPLACE FUNCTION calculate_due_date()
RETURNS TRIGGER AS $$
BEGIN
  IF NEW.due_date IS NULL THEN
    NEW.due_date := NEW.payment_date + INTERVAL '1 year';
  END IF;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER set_due_date
  BEFORE INSERT ON public.dues_payments
  FOR EACH ROW
  EXECUTE FUNCTION calculate_due_date();

-- Auto-update member status to active after payment
CREATE OR REPLACE FUNCTION update_member_status_on_payment()
RETURNS TRIGGER AS $$
DECLARE
  active_status_id UUID;
BEGIN
  SELECT id INTO active_status_id
  FROM public.membership_statuses
  WHERE name = 'active';

  UPDATE public.members
  SET membership_status_id = active_status_id,
      updated_at = NOW()
  WHERE id = NEW.member_id;

  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER activate_member_on_payment
  AFTER INSERT ON public.dues_payments
  FOR EACH ROW
  EXECUTE FUNCTION update_member_status_on_payment();

-- ============================================
-- EVENT TYPES (Admin-configurable)
-- ============================================
CREATE TABLE public.event_types (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  name TEXT NOT NULL UNIQUE,
  display_name TEXT NOT NULL,
  color TEXT NOT NULL DEFAULT '#3b82f6',
  icon TEXT,
  description TEXT,
  is_active BOOLEAN DEFAULT TRUE,
  sort_order INTEGER DEFAULT 0,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- Default event types
INSERT INTO public.event_types (name, display_name, color, icon, sort_order) VALUES
  ('social', 'Social Event', '#10b981', 'party-popper', 1),
  ('meeting', 'Meeting', '#6366f1', 'users', 2),
  ('fundraiser', 'Fundraiser', '#f59e0b', 'heart-handshake', 3),
  ('workshop', 'Workshop', '#8b5cf6', 'graduation-cap', 4),
  ('gala', 'Gala/Formal', '#ec4899', 'sparkles', 5),
  ('other', 'Other', '#6b7280', 'calendar', 6);

-- ============================================
-- EVENTS
-- ============================================
CREATE TABLE public.events (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

  -- Basic Info
  title TEXT NOT NULL,
  description TEXT,
  event_type_id UUID REFERENCES public.event_types(id),

  -- Date/Time
  start_datetime TIMESTAMPTZ NOT NULL,
  end_datetime TIMESTAMPTZ NOT NULL,
  all_day BOOLEAN DEFAULT FALSE,
  timezone TEXT DEFAULT 'Europe/Monaco',

  -- Location
  location TEXT,
  location_url TEXT,

  -- Capacity
  max_attendees INTEGER,
  max_guests_per_member INTEGER DEFAULT 1,

  -- Pricing
  is_paid BOOLEAN DEFAULT FALSE,
  member_price DECIMAL(10,2) DEFAULT 0,
  non_member_price DECIMAL(10,2) DEFAULT 0,
  pricing_notes TEXT,

  -- Visibility
  visibility TEXT NOT NULL DEFAULT 'members'
    CHECK (visibility IN ('public', 'members', 'board', 'admin')),
  status TEXT NOT NULL DEFAULT 'published'
    CHECK (status IN ('draft', 'published', 'cancelled', 'completed')),

  -- Media
  cover_image_url TEXT,

  -- Meta
  created_by UUID NOT NULL REFERENCES public.members(id),
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE TRIGGER events_updated_at
  BEFORE UPDATE ON public.events
  FOR EACH ROW
  EXECUTE FUNCTION update_updated_at();

-- ============================================
-- EVENT RSVPs (Members)
-- ============================================
CREATE TABLE public.event_rsvps (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  event_id UUID NOT NULL REFERENCES public.events(id) ON DELETE CASCADE,
  member_id UUID NOT NULL REFERENCES public.members(id) ON DELETE CASCADE,

  status TEXT NOT NULL DEFAULT 'confirmed'
    CHECK (status IN ('confirmed', 'declined', 'maybe', 'waitlist', 'cancelled')),
  guest_count INTEGER DEFAULT 0,
  guest_names TEXT[],
  notes TEXT,

  -- Payment
  payment_status TEXT DEFAULT 'not_required'
    CHECK (payment_status IN ('not_required', 'pending', 'paid')),
  payment_reference TEXT,
  payment_amount DECIMAL(10,2),

  -- Attendance
  attended BOOLEAN DEFAULT FALSE,
  checked_in_at TIMESTAMPTZ,
  checked_in_by UUID REFERENCES public.members(id),

  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW(),

  UNIQUE(event_id, member_id)
);

CREATE TRIGGER event_rsvps_updated_at
  BEFORE UPDATE ON public.event_rsvps
  FOR EACH ROW
  EXECUTE FUNCTION update_updated_at();

-- ============================================
-- EVENT RSVPs (Public/Non-members)
-- ============================================
CREATE TABLE public.event_rsvps_public (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  event_id UUID NOT NULL REFERENCES public.events(id) ON DELETE CASCADE,

  full_name TEXT NOT NULL,
  email TEXT NOT NULL,
  phone TEXT,

  status TEXT NOT NULL DEFAULT 'confirmed'
    CHECK (status IN ('confirmed', 'declined', 'maybe', 'waitlist', 'cancelled')),
  guest_count INTEGER DEFAULT 0,
  guest_names TEXT[],

  -- Payment
  payment_status TEXT DEFAULT 'not_required'
    CHECK (payment_status IN ('not_required', 'pending', 'paid')),
  payment_reference TEXT,
  payment_amount DECIMAL(10,2),

  -- Attendance
  attended BOOLEAN DEFAULT FALSE,

  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW(),

  UNIQUE(event_id, email)
);

CREATE TRIGGER event_rsvps_public_updated_at
  BEFORE UPDATE ON public.event_rsvps_public
  FOR EACH ROW
  EXECUTE FUNCTION update_updated_at();

-- ============================================
-- DOCUMENT CATEGORIES
-- ============================================
CREATE TABLE public.document_categories (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  name TEXT NOT NULL UNIQUE,
  display_name TEXT NOT NULL,
  description TEXT,
  icon TEXT,
  sort_order INTEGER DEFAULT 0,
  is_active BOOLEAN DEFAULT TRUE,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- Default categories
INSERT INTO public.document_categories (name, display_name, icon, sort_order) VALUES
  ('meeting_minutes', 'Meeting Minutes', 'file-text', 1),
  ('governance', 'Governance & Bylaws', 'scale', 2),
  ('legal', 'Legal Documents', 'briefcase', 3),
  ('financial', 'Financial Reports', 'dollar-sign', 4),
  ('member_resources', 'Member Resources', 'book-open', 5),
  ('forms', 'Forms & Templates', 'clipboard', 6),
  ('other', 'Other Documents', 'file', 7);

-- ============================================
-- DOCUMENTS
-- ============================================
CREATE TABLE public.documents (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

  title TEXT NOT NULL,
  description TEXT,
  category_id UUID REFERENCES public.document_categories(id),

  -- File Info
  file_path TEXT NOT NULL,
  file_name TEXT NOT NULL,
  file_size INTEGER NOT NULL,
  mime_type TEXT NOT NULL,

  -- Visibility
  visibility TEXT NOT NULL DEFAULT 'members'
    CHECK (visibility IN ('public', 'members', 'board', 'admin')),
  allowed_member_ids UUID[],

  -- Version tracking
  version INTEGER DEFAULT 1,
  replaces_document_id UUID REFERENCES public.documents(id),

  -- Meeting-specific fields
  meeting_date DATE,
  meeting_attendees UUID[],

  -- Meta
  uploaded_by UUID NOT NULL REFERENCES public.members(id),
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE TRIGGER documents_updated_at
  BEFORE UPDATE ON public.documents
  FOR EACH ROW
  EXECUTE FUNCTION update_updated_at();

-- ============================================
-- APP SETTINGS (Unified key-value store)
-- ============================================
CREATE TABLE public.app_settings (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  category TEXT NOT NULL,
  setting_key TEXT NOT NULL,
  setting_value JSONB NOT NULL,
  setting_type TEXT NOT NULL DEFAULT 'text'
    CHECK (setting_type IN ('text', 'number', 'boolean', 'json', 'array')),
  display_name TEXT NOT NULL,
  description TEXT,
  is_public BOOLEAN DEFAULT FALSE,
  updated_at TIMESTAMPTZ DEFAULT NOW(),
  updated_by UUID REFERENCES public.members(id),

  UNIQUE(category, setting_key)
);

-- Default settings
INSERT INTO public.app_settings (category, setting_key, setting_value, setting_type, display_name, description, is_public) VALUES
  -- Organization
  ('organization', 'association_name', '"Monaco USA"', 'text', 'Association Name', 'Official name of the association', true),
  ('organization', 'tagline', '"Americans in Monaco"', 'text', 'Tagline', 'Association tagline shown on login', true),
  ('organization', 'contact_email', '"contact@monacousa.org"', 'text', 'Contact Email', 'Public contact email', true),
  ('organization', 'primary_color', '"#dc2626"', 'text', 'Primary Color', 'Brand primary color (hex)', true),

  -- Dues
  ('dues', 'payment_iban', '"[REDACTED]"', 'text', 'Payment IBAN', 'Bank IBAN for dues', false),
  ('dues', 'payment_account_holder', '"ASSOCIATION MONACO USA"', 'text', 'Account Holder', 'Bank account holder name', false),
  ('dues', 'payment_bank_name', '"Credit Foncier de Monaco"', 'text', 'Bank Name', 'Name of the bank', false),
  ('dues', 'reminder_days_before', '[30, 7, 1]', 'array', 'Reminder Days', 'Days before due to send reminders', false),
  ('dues', 'grace_period_days', '30', 'number', 'Grace Period', 'Days after due before auto-inactive', false),
  ('dues', 'auto_inactive_enabled', 'true', 'boolean', 'Auto Inactive', 'Auto set inactive after grace period', false),

  -- System
  ('system', 'maintenance_mode', 'false', 'boolean', 'Maintenance Mode', 'Put portal in maintenance mode', false),
  ('system', 'max_upload_size_mb', '50', 'number', 'Max Upload Size', 'Maximum file upload size in MB', false);

-- ============================================
-- EMAIL TEMPLATES
-- ============================================
CREATE TABLE public.email_templates (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  template_key TEXT UNIQUE NOT NULL,
  template_name TEXT NOT NULL,
  category TEXT NOT NULL,
  subject TEXT NOT NULL,
  body_html TEXT NOT NULL,
  body_text TEXT,
  is_active BOOLEAN DEFAULT TRUE,
  is_system BOOLEAN DEFAULT FALSE,
  variables_schema JSONB,
  preview_data JSONB,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW(),
  updated_by UUID REFERENCES public.members(id)
);

CREATE TRIGGER email_templates_updated_at
  BEFORE UPDATE ON public.email_templates
  FOR EACH ROW
  EXECUTE FUNCTION update_updated_at();

-- ============================================
-- EMAIL LOGS
-- ============================================
CREATE TABLE public.email_logs (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  recipient_id UUID REFERENCES public.members(id),
  recipient_email TEXT NOT NULL,
  recipient_name TEXT,
  template_key TEXT,
  subject TEXT NOT NULL,
  email_type TEXT NOT NULL,
  status TEXT NOT NULL DEFAULT 'queued'
    CHECK (status IN ('queued', 'sent', 'delivered', 'opened', 'clicked', 'bounced', 'failed')),
  provider TEXT,
  provider_message_id TEXT,
  opened_at TIMESTAMPTZ,
  clicked_at TIMESTAMPTZ,
  error_message TEXT,
  retry_count INTEGER DEFAULT 0,
  template_variables JSONB,
  sent_by UUID REFERENCES public.members(id),
  created_at TIMESTAMPTZ DEFAULT NOW(),
  sent_at TIMESTAMPTZ,
  delivered_at TIMESTAMPTZ
);

-- ============================================
-- VIEWS
-- ============================================

-- Members with dues status
CREATE VIEW public.members_with_dues AS
SELECT
  m.*,
  ms.name as status_name,
  ms.display_name as status_display_name,
  ms.color as status_color,
  mt.display_name as membership_type_name,
  mt.annual_dues,
  dp.last_payment_date,
  dp.current_due_date,
  CASE
    WHEN dp.current_due_date IS NULL THEN 'never_paid'
    WHEN dp.current_due_date < CURRENT_DATE THEN 'overdue'
    WHEN dp.current_due_date < CURRENT_DATE + INTERVAL '30 days' THEN 'due_soon'
    ELSE 'current'
  END as dues_status,
  CASE
    WHEN dp.current_due_date < CURRENT_DATE
    THEN (CURRENT_DATE - dp.current_due_date)::INTEGER
    ELSE NULL
  END as days_overdue,
  CASE
    WHEN dp.current_due_date >= CURRENT_DATE
    THEN (dp.current_due_date - CURRENT_DATE)::INTEGER
    ELSE NULL
  END as days_until_due
FROM public.members m
LEFT JOIN public.membership_statuses ms ON m.membership_status_id = ms.id
LEFT JOIN public.membership_types mt ON m.membership_type_id = mt.id
LEFT JOIN LATERAL (
  SELECT
    payment_date as last_payment_date,
    due_date as current_due_date
  FROM public.dues_payments
  WHERE member_id = m.id
  ORDER BY due_date DESC
  LIMIT 1
) dp ON true;

-- Events with attendee counts
CREATE VIEW public.events_with_counts AS
SELECT
  e.*,
  et.display_name as event_type_name,
  et.color as event_type_color,
  et.icon as event_type_icon,
  COALESCE(member_rsvps.confirmed_count, 0) +
    COALESCE(member_rsvps.guest_count, 0) +
    COALESCE(public_rsvps.confirmed_count, 0) +
    COALESCE(public_rsvps.guest_count, 0) as total_attendees,
  COALESCE(member_rsvps.confirmed_count, 0) as member_count,
  COALESCE(public_rsvps.confirmed_count, 0) as non_member_count,
  COALESCE(member_rsvps.waitlist_count, 0) +
    COALESCE(public_rsvps.waitlist_count, 0) as waitlist_count,
  CASE
    WHEN e.max_attendees IS NULL THEN FALSE
    WHEN (COALESCE(member_rsvps.confirmed_count, 0) +
          COALESCE(member_rsvps.guest_count, 0) +
          COALESCE(public_rsvps.confirmed_count, 0) +
          COALESCE(public_rsvps.guest_count, 0)) >= e.max_attendees THEN TRUE
    ELSE FALSE
  END as is_full
FROM public.events e
LEFT JOIN public.event_types et ON e.event_type_id = et.id
LEFT JOIN LATERAL (
  SELECT
    COUNT(*) FILTER (WHERE status = 'confirmed') as confirmed_count,
    COALESCE(SUM(guest_count) FILTER (WHERE status = 'confirmed'), 0) as guest_count,
    COUNT(*) FILTER (WHERE status = 'waitlist') as waitlist_count
  FROM public.event_rsvps
  WHERE event_id = e.id
) member_rsvps ON true
LEFT JOIN LATERAL (
  SELECT
    COUNT(*) FILTER (WHERE status = 'confirmed') as confirmed_count,
    COALESCE(SUM(guest_count) FILTER (WHERE status = 'confirmed'), 0) as guest_count,
    COUNT(*) FILTER (WHERE status = 'waitlist') as waitlist_count
  FROM public.event_rsvps_public
  WHERE event_id = e.id
) public_rsvps ON true;

-- ============================================
-- ROW LEVEL SECURITY
-- ============================================

-- Enable RLS on all tables
ALTER TABLE public.members ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.dues_payments ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.events ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.event_rsvps ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.event_rsvps_public ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.documents ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.app_settings ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.email_templates ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.email_logs ENABLE ROW LEVEL SECURITY;

-- MEMBERS POLICIES
CREATE POLICY "Members viewable by authenticated users"
  ON public.members FOR SELECT
  TO authenticated
  USING (true);

CREATE POLICY "Users can update own profile"
  ON public.members FOR UPDATE
  TO authenticated
  USING (auth.uid() = id);

CREATE POLICY "Admins can insert members"
  ON public.members FOR INSERT
  TO authenticated
  WITH CHECK (
    EXISTS (SELECT 1 FROM public.members WHERE id = auth.uid() AND role = 'admin')
    OR auth.uid() = id
  );

CREATE POLICY "Admins can delete members"
  ON public.members FOR DELETE
  TO authenticated
  USING (
    EXISTS (SELECT 1 FROM public.members WHERE id = auth.uid() AND role = 'admin')
  );

-- DUES PAYMENTS POLICIES
CREATE POLICY "Own payments viewable"
  ON public.dues_payments FOR SELECT
  TO authenticated
  USING (
    member_id = auth.uid()
    OR EXISTS (SELECT 1 FROM public.members WHERE id = auth.uid() AND role IN ('board', 'admin'))
  );

CREATE POLICY "Board can record payments"
  ON public.dues_payments FOR INSERT
  TO authenticated
  WITH CHECK (
    EXISTS (SELECT 1 FROM public.members WHERE id = auth.uid() AND role IN ('board', 'admin'))
  );

-- EVENTS POLICIES
CREATE POLICY "Events viewable based on visibility"
  ON public.events FOR SELECT
  TO authenticated
  USING (
    visibility = 'members'
    OR visibility = 'public'
    OR (visibility = 'board' AND EXISTS (
      SELECT 1 FROM public.members WHERE id = auth.uid() AND role IN ('board', 'admin')
    ))
    OR (visibility = 'admin' AND EXISTS (
      SELECT 1 FROM public.members WHERE id = auth.uid() AND role = 'admin'
    ))
  );

CREATE POLICY "Public events viewable by anyone"
  ON public.events FOR SELECT
  TO anon
  USING (visibility = 'public' AND status = 'published');

CREATE POLICY "Board can manage events"
  ON public.events FOR ALL
  TO authenticated
  USING (
    EXISTS (SELECT 1 FROM public.members WHERE id = auth.uid() AND role IN ('board', 'admin'))
  );

-- EVENT RSVPs POLICIES
CREATE POLICY "RSVPs viewable by member and board"
  ON public.event_rsvps FOR SELECT
  TO authenticated
  USING (
    member_id = auth.uid()
    OR EXISTS (SELECT 1 FROM public.members WHERE id = auth.uid() AND role IN ('board', 'admin'))
  );

CREATE POLICY "Members can manage own RSVPs"
  ON public.event_rsvps FOR ALL
  TO authenticated
  USING (member_id = auth.uid())
  WITH CHECK (member_id = auth.uid());

CREATE POLICY "Board can manage all RSVPs"
  ON public.event_rsvps FOR ALL
  TO authenticated
  USING (
    EXISTS (SELECT 1 FROM public.members WHERE id = auth.uid() AND role IN ('board', 'admin'))
  );

-- PUBLIC RSVPs POLICIES
CREATE POLICY "Public RSVPs viewable by board"
  ON public.event_rsvps_public FOR SELECT
  TO authenticated
  USING (
    EXISTS (SELECT 1 FROM public.members WHERE id = auth.uid() AND role IN ('board', 'admin'))
  );

CREATE POLICY "Anyone can create public RSVP"
  ON public.event_rsvps_public FOR INSERT
  TO anon, authenticated
  WITH CHECK (true);

CREATE POLICY "Board can manage public RSVPs"
  ON public.event_rsvps_public FOR ALL
  TO authenticated
  USING (
    EXISTS (SELECT 1 FROM public.members WHERE id = auth.uid() AND role IN ('board', 'admin'))
  );

-- DOCUMENTS POLICIES
CREATE POLICY "Documents viewable based on visibility"
  ON public.documents FOR SELECT
  TO authenticated
  USING (
    visibility = 'members'
    OR visibility = 'public'
    OR (visibility = 'board' AND EXISTS (
      SELECT 1 FROM public.members WHERE id = auth.uid() AND role IN ('board', 'admin')
    ))
    OR (visibility = 'admin' AND EXISTS (
      SELECT 1 FROM public.members WHERE id = auth.uid() AND role = 'admin'
    ))
    OR (allowed_member_ids IS NOT NULL AND auth.uid() = ANY(allowed_member_ids))
  );

CREATE POLICY "Board can upload documents"
  ON public.documents FOR INSERT
  TO authenticated
  WITH CHECK (
    EXISTS (SELECT 1 FROM public.members WHERE id = auth.uid() AND role IN ('board', 'admin'))
  );

CREATE POLICY "Admin can manage all documents"
  ON public.documents FOR ALL
  TO authenticated
  USING (
    EXISTS (SELECT 1 FROM public.members WHERE id = auth.uid() AND role = 'admin')
  );

-- APP SETTINGS POLICIES
CREATE POLICY "Public settings viewable by anyone"
  ON public.app_settings FOR SELECT
  USING (is_public = true);

CREATE POLICY "All settings viewable by admin"
  ON public.app_settings FOR SELECT
  TO authenticated
  USING (
    EXISTS (SELECT 1 FROM public.members WHERE id = auth.uid() AND role = 'admin')
  );

CREATE POLICY "Admin can manage settings"
  ON public.app_settings FOR ALL
  TO authenticated
  USING (
    EXISTS (SELECT 1 FROM public.members WHERE id = auth.uid() AND role = 'admin')
  );

-- EMAIL TEMPLATES POLICIES
CREATE POLICY "Admin can manage email templates"
  ON public.email_templates FOR ALL
  TO authenticated
  USING (
    EXISTS (SELECT 1 FROM public.members WHERE id = auth.uid() AND role = 'admin')
  );

-- EMAIL LOGS POLICIES
CREATE POLICY "Own email logs viewable"
  ON public.email_logs FOR SELECT
  TO authenticated
  USING (
    recipient_id = auth.uid()
    OR EXISTS (SELECT 1 FROM public.members WHERE id = auth.uid() AND role = 'admin')
  );

CREATE POLICY "Admin can manage email logs"
  ON public.email_logs FOR ALL
  TO authenticated
  USING (
    EXISTS (SELECT 1 FROM public.members WHERE id = auth.uid() AND role = 'admin')
  );

-- ============================================
-- INDEXES
-- ============================================
CREATE INDEX idx_members_email ON public.members(email);
CREATE INDEX idx_members_member_id ON public.members(member_id);
CREATE INDEX idx_members_role ON public.members(role);
CREATE INDEX idx_members_status ON public.members(membership_status_id);

CREATE INDEX idx_dues_payments_member ON public.dues_payments(member_id);
CREATE INDEX idx_dues_payments_date ON public.dues_payments(payment_date DESC);

CREATE INDEX idx_events_start ON public.events(start_datetime);
CREATE INDEX idx_events_visibility ON public.events(visibility);
CREATE INDEX idx_events_status ON public.events(status);

CREATE INDEX idx_event_rsvps_event ON public.event_rsvps(event_id);
CREATE INDEX idx_event_rsvps_member ON public.event_rsvps(member_id);

CREATE INDEX idx_documents_category ON public.documents(category_id);
CREATE INDEX idx_documents_visibility ON public.documents(visibility);

CREATE INDEX idx_app_settings_category ON public.app_settings(category, setting_key);

CREATE INDEX idx_email_logs_recipient ON public.email_logs(recipient_id);
CREATE INDEX idx_email_logs_status ON public.email_logs(status);
CREATE INDEX idx_email_logs_created ON public.email_logs(created_at DESC);
