-- User Suspensions Migration
-- Adds user_suspensions table for admin suspend/ban controls

-- 1. Create suspension type enum
DROP TYPE IF EXISTS public.suspension_type CASCADE;
CREATE TYPE public.suspension_type AS ENUM ('suspended', 'banned');

-- 2. Create user_suspensions table
CREATE TABLE IF NOT EXISTS public.user_suspensions (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID NOT NULL REFERENCES public.user_profiles(id) ON DELETE CASCADE,
  suspended_by UUID NOT NULL REFERENCES public.user_profiles(id) ON DELETE CASCADE,
  suspension_type public.suspension_type NOT NULL DEFAULT 'suspended',
  reason TEXT NOT NULL,
  duration_days INTEGER NULL, -- NULL = permanent (ban)
  expires_at TIMESTAMPTZ NULL, -- NULL = permanent
  is_active BOOLEAN NOT NULL DEFAULT true,
  lifted_at TIMESTAMPTZ NULL,
  lifted_by UUID NULL REFERENCES public.user_profiles(id) ON DELETE SET NULL,
  lift_reason TEXT NULL,
  email_sent BOOLEAN NOT NULL DEFAULT false,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

-- 3. Indexes
CREATE INDEX IF NOT EXISTS idx_user_suspensions_user_id ON public.user_suspensions(user_id);
CREATE INDEX IF NOT EXISTS idx_user_suspensions_active ON public.user_suspensions(user_id, is_active);
CREATE INDEX IF NOT EXISTS idx_user_suspensions_expires_at ON public.user_suspensions(expires_at) WHERE is_active = true;

-- 4. Add suspension_status column to user_profiles if not exists
ALTER TABLE public.user_profiles
  ADD COLUMN IF NOT EXISTS suspension_status TEXT DEFAULT NULL,
  ADD COLUMN IF NOT EXISTS suspension_reason TEXT DEFAULT NULL,
  ADD COLUMN IF NOT EXISTS suspended_until TIMESTAMPTZ DEFAULT NULL;

-- 5. Helper function: check if user is currently suspended
CREATE OR REPLACE FUNCTION public.is_user_suspended(p_user_id UUID)
RETURNS BOOLEAN
LANGUAGE sql
STABLE
SECURITY DEFINER
AS $$
  SELECT EXISTS (
    SELECT 1 FROM public.user_suspensions
    WHERE user_id = p_user_id
      AND is_active = true
      AND (expires_at IS NULL OR expires_at > now())
  )
$$;

-- 6. Helper function: get active suspension for user
CREATE OR REPLACE FUNCTION public.get_active_suspension(p_user_id UUID)
RETURNS TABLE(
  suspension_id UUID,
  suspension_type TEXT,
  reason TEXT,
  expires_at TIMESTAMPTZ,
  created_at TIMESTAMPTZ
)
LANGUAGE sql
STABLE
SECURITY DEFINER
AS $$
  SELECT id, suspension_type::TEXT, reason, expires_at, created_at
  FROM public.user_suspensions
  WHERE user_id = p_user_id
    AND is_active = true
    AND (expires_at IS NULL OR expires_at > now())
  ORDER BY created_at DESC
  LIMIT 1
$$;

-- 7. Function to auto-expire suspensions
CREATE OR REPLACE FUNCTION public.expire_suspensions()
RETURNS void
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
BEGIN
  UPDATE public.user_suspensions
  SET is_active = false, updated_at = now()
  WHERE is_active = true
    AND expires_at IS NOT NULL
    AND expires_at <= now();

  -- Sync user_profiles suspension_status
  UPDATE public.user_profiles
  SET suspension_status = NULL,
      suspension_reason = NULL,
      suspended_until = NULL
  WHERE id IN (
    SELECT DISTINCT user_id FROM public.user_suspensions
    WHERE is_active = false
      AND expires_at IS NOT NULL
      AND expires_at <= now()
  )
  AND NOT public.is_user_suspended(id);
END;
$$;

-- 8. Enable RLS
ALTER TABLE public.user_suspensions ENABLE ROW LEVEL SECURITY;

-- 9. RLS Policies
DROP POLICY IF EXISTS "admins_manage_suspensions" ON public.user_suspensions;
CREATE POLICY "admins_manage_suspensions"
ON public.user_suspensions
FOR ALL
TO authenticated
USING (
  EXISTS (
    SELECT 1 FROM public.user_profiles
    WHERE id = auth.uid() AND role IN ('admin', 'moderator')
  )
)
WITH CHECK (
  EXISTS (
    SELECT 1 FROM public.user_profiles
    WHERE id = auth.uid() AND role IN ('admin', 'moderator')
  )
);

DROP POLICY IF EXISTS "users_view_own_suspension" ON public.user_suspensions;
CREATE POLICY "users_view_own_suspension"
ON public.user_suspensions
FOR SELECT
TO authenticated
USING (user_id = auth.uid());
