// ============================================================
// REQUIRED ROW LEVEL SECURITY POLICIES
// Run these in Supabase Dashboard → SQL Editor
// ============================================================
// Enable RLS:
// ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
// ALTER TABLE projects ENABLE ROW LEVEL SECURITY;
// ALTER TABLE tasks ENABLE ROW LEVEL SECURITY;
// ALTER TABLE marketplace_cart_item ENABLE ROW LEVEL SECURITY;
// ALTER TABLE marketplace_wish_list ENABLE ROW LEVEL SECURITY;
// ALTER TABLE marketplace_orders ENABLE ROW LEVEL SECURITY;
// ALTER TABLE communitypost ENABLE ROW LEVEL SECURITY;
// ALTER TABLE postcomment ENABLE ROW LEVEL SECURITY;
// ALTER TABLE contentreport ENABLE ROW LEVEL SECURITY;
// ALTER TABLE jobapplication ENABLE ROW LEVEL SECURITY;
// ALTER TABLE savedjobsearch ENABLE ROW LEVEL SECURITY;
// ALTER TABLE supportrequest ENABLE ROW LEVEL SECURITY;
//
// profiles: read all, update own
// CREATE POLICY "profiles_read_all" ON profiles FOR SELECT USING (true);
// CREATE POLICY "profiles_update_own" ON profiles FOR UPDATE USING (auth.uid() = id);
//
// projects: own only
// CREATE POLICY "projects_own" ON projects USING (auth.uid() = user_id);
//
// tasks: accessible if user owns parent project
// CREATE POLICY "tasks_via_project" ON tasks USING (EXISTS (SELECT 1 FROM projects WHERE projects.id = tasks.project_id AND projects.user_id = auth.uid()));
//
// cart/wishlist/orders/applications/saved searches/support: own only
// CREATE POLICY "cart_own" ON marketplace_cart_item USING (auth.uid() = user_id);
// CREATE POLICY "wishlist_own" ON marketplace_wish_list USING (auth.uid() = user_id);
// CREATE POLICY "orders_own" ON marketplace_orders USING (auth.uid() = user_id);
// CREATE POLICY "applications_own" ON jobapplication USING (auth.uid() = applicant_id);
// CREATE POLICY "saved_searches_own" ON savedjobsearch USING (auth.uid() = user_id);
// CREATE POLICY "support_own" ON supportrequest USING (auth.uid() = user_id);
//
// community: read all, insert/delete own
// CREATE POLICY "posts_read" ON communitypost FOR SELECT USING (true);
// CREATE POLICY "posts_insert_own" ON communitypost FOR INSERT WITH CHECK (auth.uid() = user_id);
// CREATE POLICY "posts_delete_own" ON communitypost FOR DELETE USING (auth.uid() = user_id);
// CREATE POLICY "comments_read" ON postcomment FOR SELECT USING (true);
// CREATE POLICY "comments_insert_own" ON postcomment FOR INSERT WITH CHECK (auth.uid() = user_id);
//
// content reports: insert any, select own + admin, update admin
// CREATE POLICY "reports_insert" ON contentreport FOR INSERT WITH CHECK (auth.uid() = reporter_id);
// CREATE POLICY "reports_read_own" ON contentreport FOR SELECT USING (auth.uid() = reporter_id OR EXISTS (SELECT 1 FROM profiles WHERE profiles.id = auth.uid() AND profiles.role = 'admin'));
// CREATE POLICY "reports_update_admin" ON contentreport FOR UPDATE USING (EXISTS (SELECT 1 FROM profiles WHERE profiles.id = auth.uid() AND profiles.role = 'admin'));
// ============================================================

// ============================================================
// DB OPTIMIZATION INDEXES
// Run these in Supabase Dashboard → SQL Editor
// ============================================================
// CREATE INDEX IF NOT EXISTS idx_cart_user ON marketplace_cart_item(user_id);
// CREATE INDEX IF NOT EXISTS idx_wishlist_user ON marketplace_wish_list(user_id);
// CREATE INDEX IF NOT EXISTS idx_products_category ON marketplace_product(category);
// CREATE INDEX IF NOT EXISTS idx_orders_user ON marketplace_orders(user_id);
// CREATE INDEX IF NOT EXISTS idx_job_status ON job(status);
// CREATE INDEX IF NOT EXISTS idx_job_user ON job(user_id);
// CREATE INDEX IF NOT EXISTS idx_application_applicant ON jobapplication(applicant_id);
// CREATE INDEX IF NOT EXISTS idx_application_job ON jobapplication(job_id);
// CREATE INDEX IF NOT EXISTS idx_post_created ON communitypost(created_at DESC);
// CREATE INDEX IF NOT EXISTS idx_post_upvotes ON communitypost(upvote_count DESC);
// CREATE INDEX IF NOT EXISTS idx_comment_post ON postcomment(post_id);
// CREATE INDEX IF NOT EXISTS idx_report_status ON contentreport(status);
// CREATE INDEX IF NOT EXISTS idx_token_events_user ON token_events(user_id, created_at DESC);
// CREATE INDEX IF NOT EXISTS idx_user_achievements_user ON user_achievements(user_id);
// CREATE INDEX IF NOT EXISTS idx_contentreport_reviewer ON contentreport(reviewer_id) WHERE reviewer_id IS NOT NULL;
// CREATE INDEX IF NOT EXISTS idx_orders_status ON marketplace_orders(status);
// CREATE INDEX IF NOT EXISTS idx_supportrequest_user ON supportrequest(user_id);
// CREATE INDEX IF NOT EXISTS idx_profiles_role ON profiles(role);
// ============================================================

// Additional tables:
// ALTER TABLE marketplace_orders_payments ENABLE ROW LEVEL SECURITY;
// ALTER TABLE post_upvote ENABLE ROW LEVEL SECURITY;
// ALTER TABLE marketplace_product_review ENABLE ROW LEVEL SECURITY;
// ALTER TABLE token_events ENABLE ROW LEVEL SECURITY;
// ALTER TABLE user_achievements ENABLE ROW LEVEL SECURITY;
// ALTER TABLE admin_audit_log ENABLE ROW LEVEL SECURITY;
// ALTER TABLE newsletter_subscriber ENABLE ROW LEVEL SECURITY;
//
// CREATE POLICY "payments_own" ON marketplace_orders_payments USING (EXISTS (SELECT 1 FROM marketplace_orders WHERE marketplace_orders.id = marketplace_orders_payments.order_id AND marketplace_orders.user_id = auth.uid()));
// CREATE POLICY "upvotes_own" ON post_upvote USING (auth.uid() = user_id);
// CREATE POLICY "reviews_read" ON marketplace_product_review FOR SELECT USING (true);
// CREATE POLICY "reviews_insert_own" ON marketplace_product_review FOR INSERT WITH CHECK (auth.uid() = user_id);
// CREATE POLICY "token_events_own" ON token_events USING (auth.uid() = user_id);
// CREATE POLICY "achievements_own" ON user_achievements USING (auth.uid() = user_id);
// CREATE POLICY "audit_log_admin" ON admin_audit_log USING (EXISTS (SELECT 1 FROM profiles WHERE profiles.id = auth.uid() AND profiles.role = 'admin'));
// CREATE POLICY "newsletter_insert" ON newsletter_subscriber FOR INSERT WITH CHECK (true);
// ============================================================

// ---- Supabase client initialization ----
// Replace with your Supabase project URL and anon key from the Supabase dashboard → Settings → API
const SUPABASE_URL = 'https://nkfbcxpdehtirinagygv.supabase.co';
const SUPABASE_ANON_KEY = 'sb_publishable_9lYe9J9Eq7wmB7NFAtgh7A_kJ1b3m_G';
const db = supabase.createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
window.db = db;

// ---- React hook destructuring (no ES module imports in standalone Babel) ----
const { useState, useEffect, useContext, createContext, useRef, useCallback } = React;

// ---- Auth Context ----
const AuthCtx = createContext(null);
window.AuthCtx = AuthCtx;

function AuthProvider({ children }) {
  const [user, setUser] = useState(null);
  const [session, setSession] = useState(null);
  const [loading, setLoading] = useState(true);
  const [profile, setProfile] = useState(null);
  const [profileLoading, setProfileLoading] = useState(false);
  const [profileError, setProfileError] = useState(null);
  const [notifications, setNotifications] = useState([]);
  const [unreadCount, setUnreadCount] = useState(0);

  // Fetch or create profile row
  const fetchOrCreateProfile = useCallback(async (authUser) => {
    setProfileLoading(true);
    setProfileError(null);
    try {
      const { data, error } = await db.from('profiles').select('*').eq('id', authUser.id).single();
      if (error && error.code !== 'PGRST116') {
        setProfileError(error.message);
        setProfileLoading(false);
        return;
      }
      if (!data) {
        // Profile row doesn't exist — insert one
        await db.from('profiles').insert({
          id: authUser.id,
          username: authUser.user_metadata?.username || '',
          email: authUser.email,
          role: authUser.user_metadata?.role || 'creator',
          created_at: new Date().toISOString(),
        });
        // Re-fetch after insert
        const { data: newData, error: newError } = await db.from('profiles').select('*').eq('id', authUser.id).single();
        if (newError) { setProfileError(newError.message); }
        else { setProfile(newData); }
      } else {
        setProfile(data);
      }
    } catch (err) {
      setProfileError(err.message);
    } finally {
      setProfileLoading(false);
    }
  }, []);

  const appendNotification = useCallback((notif) => {
    setNotifications(prev => [notif, ...prev]);
    setUnreadCount(prev => prev + 1);
  }, []);

  // Subscribe to auth state changes
  useEffect(() => {
    let notifChannel = null;

    // Check existing session on mount
    db.auth.getSession().then(({ data: { session: s } }) => {
      setSession(s);
      setUser(s?.user ?? null);
      if (s?.user) {
        fetchOrCreateProfile(s.user);
      }
      setLoading(false);
    }).catch(() => {
      setLoading(false);
    });

    const { data: { subscription } } = db.auth.onAuthStateChange(async (event, s) => {
      setSession(s);
      setUser(s?.user ?? null);

      if (s?.user) {
        fetchOrCreateProfile(s.user);

        // Subscribe to notifications channel for this user
        if (notifChannel) db.removeChannel(notifChannel);
        notifChannel = db.channel('user-notifications:' + s.user.id)
          .on('postgres_changes', {
            event: 'INSERT', schema: 'public', table: 'notifications',
            filter: 'user_id=eq.' + s.user.id,
          }, (payload) => {
            appendNotification(payload.new);
          })
          .subscribe();
      } else {
        // SIGNED_OUT
        setProfile(null);
        setProfileLoading(false);
        setProfileError(null);
        setNotifications([]);
        setUnreadCount(0);
        if (notifChannel) {
          db.removeChannel(notifChannel);
          notifChannel = null;
        }
      }

      if (event !== 'INITIAL_SESSION') {
        setLoading(false);
      }
    });

    return () => {
      subscription.unsubscribe();
      if (notifChannel) db.removeChannel(notifChannel);
    };
  }, [fetchOrCreateProfile, appendNotification]);

  // Auth methods
  const signIn = async (email, password) => {
    const { error } = await db.auth.signInWithPassword({ email, password });
    return { error };
  };

  const signUp = async (email, password, metadata) => {
    const { error } = await db.auth.signUp({
      email,
      password,
      options: {
        data: metadata,
        emailRedirectTo: window.location.origin,
      },
    });
    return { error };
  };

  const signOut = async () => {
    await db.auth.signOut();
  };

  const signInWithGoogle = () => {
    return db.auth.signInWithOAuth({
      provider: 'google',
      options: { redirectTo: window.location.origin },
    });
  };

  // Refresh profile from DB (call after profile updates)
  const refreshProfile = useCallback(async () => {
    if (!user) return;
    const { data } = await db.from('profiles').select('*').eq('id', user.id).single();
    if (data) setProfile(data);
  }, [user]);

  const value = {
    user, session, loading,
    signIn, signUp, signOut, signInWithGoogle,
    profile, profileLoading, profileError, refreshProfile,
    notifications, unreadCount, appendNotification,
    setUnreadCount,
  };

  // While loading, show full-screen loading state
  if (loading) {
    return (
      <div style={{
        position: 'fixed', inset: 0, background: '#000',
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        zIndex: 9999,
      }}>
        <div style={{
          fontFamily: "'IBM Plex Mono', ui-monospace, Menlo, monospace",
          fontSize: 14, color: 'var(--accent, #39FF6A)',
          letterSpacing: 3, textTransform: 'uppercase',
        }}>// LOADING SESSION…</div>
      </div>
    );
  }

  return (
    <AuthCtx.Provider value={value}>
      {children}
    </AuthCtx.Provider>
  );
}

function useAuth() {
  const ctx = useContext(AuthCtx);
  if (!ctx) throw new Error('useAuth must be used inside AuthProvider');
  return ctx;
}

function useRequireAuth(navigate) {
  const { user, loading } = useAuth();
  useEffect(() => {
    if (!loading && user === null) {
      navigate('login');
    }
  }, [user, loading, navigate]);
}

// ---- useQuery hook ----
// Manages data/loading/error state for async queries
function useQuery(queryFn, deps) {
  const [state, setState] = useState({ data: null, loading: true, error: null });
  const cancelledRef = useRef(false);

  const run = useCallback(async () => {
    cancelledRef.current = false;
    setState(s => ({ ...s, loading: true, error: null }));
    try {
      const result = await queryFn();
      if (cancelledRef.current) return;
      const { data, error } = result || {};
      if (error) {
        // Handle auth errors
        if (error.message && (error.message.includes('JWT expired') || error.message.includes('not authenticated'))) {
          db.auth.signOut();
          window.dispatchEvent(new Event('vlstudio:auth-expired'));
        }
        if (error.message && error.message.includes('Failed to fetch')) {
          window.dispatchEvent(new CustomEvent('vlstudio:offline'));
        }
        setState({ data: null, loading: false, error });
      } else {
        setState({ data, loading: false, error: null });
      }
    } catch (err) {
      if (cancelledRef.current) return;
      if (err.message && (err.message.includes('JWT expired') || err.message.includes('not authenticated'))) {
        db.auth.signOut();
        window.dispatchEvent(new Event('vlstudio:auth-expired'));
      }
      if (err.message && err.message.includes('Failed to fetch')) {
        window.dispatchEvent(new CustomEvent('vlstudio:offline'));
      }
      setState({ data: null, loading: false, error: err });
    }
  }, deps); // eslint-disable-line react-hooks/exhaustive-deps

  useEffect(() => {
    run();
    return () => { cancelledRef.current = true; };
  }, [run]);

  return { ...state, refetch: run };
}

// ---- useMutation hook ----
function useMutation(mutateFn) {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  const mutate = async (args) => {
    setLoading(true);
    setError(null);
    try {
      const result = await mutateFn(args);
      const { data, error: err } = result || {};
      if (err) {
        if (err.message && (err.message.includes('JWT expired') || err.message.includes('not authenticated'))) {
          db.auth.signOut();
          window.dispatchEvent(new Event('vlstudio:auth-expired'));
        }
        if (err.message && err.message.includes('Failed to fetch')) {
          window.dispatchEvent(new CustomEvent('vlstudio:offline'));
        }
        setError(err);
        setLoading(false);
        return { data: null, error: err };
      }
      setLoading(false);
      return { data, error: null };
    } catch (err) {
      if (err.message && (err.message.includes('JWT expired') || err.message.includes('not authenticated'))) {
        db.auth.signOut();
        window.dispatchEvent(new Event('vlstudio:auth-expired'));
      }
      if (err.message && err.message.includes('Failed to fetch')) {
        window.dispatchEvent(new CustomEvent('vlstudio:offline'));
      }
      setError(err);
      setLoading(false);
      return { data: null, error: err };
    }
  };

  return { mutate, loading, error };
}

// ---- formatRelativeTime helper ----
function formatRelativeTime(dateString) {
  if (!dateString) return '';
  const date = new Date(dateString);
  const now = new Date();
  const diffMs = now - date;
  const diffSec = Math.floor(diffMs / 1000);
  const diffMin = Math.floor(diffSec / 60);
  const diffHr = Math.floor(diffMin / 60);
  const diffDays = Math.floor(diffHr / 24);

  if (diffSec < 60) return 'just now';
  if (diffHr < 1) return `${diffMin}m ago`;
  if (diffHr < 24) return `${diffHr}h ago`;
  if (diffDays === 1) return 'yesterday';
  return `${diffDays} days ago`;
}

// ---- Export everything to window ----
window.AuthProvider = AuthProvider;
window.useAuth = useAuth;
window.useRequireAuth = useRequireAuth;
window.useQuery = useQuery;
window.useMutation = useMutation;
window.formatRelativeTime = formatRelativeTime;
