// Supabase Edge Function — mints a short-lived LiveKit access token after
// verifying that the caller is an accepted member of the target conversation.
//
// The LiveKit secret never leaves the server. Clients POST { conversationId }
// with their Supabase JWT and receive { token, url, roomName, identity }.

// deno-lint-ignore-file no-explicit-any
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.46.0';
import { SignJWT } from 'https://esm.sh/jose@5.9.6';

const CORS_HEADERS = {
  'access-control-allow-origin': '*',
  'access-control-allow-headers':
    'authorization, x-client-info, apikey, content-type',
  'access-control-allow-methods': 'POST, OPTIONS',
};

interface RequestBody {
  conversationId?: string;
}

Deno.serve(async (req) => {
  if (req.method === 'OPTIONS') {
    return new Response(null, { headers: CORS_HEADERS });
  }
  if (req.method !== 'POST') {
    return json({ error: 'method-not-allowed' }, 405);
  }

  const apiKey = Deno.env.get('LIVEKIT_API_KEY');
  const apiSecret = Deno.env.get('LIVEKIT_API_SECRET');
  const livekitUrl = Deno.env.get('LIVEKIT_URL');
  if (!apiKey || !apiSecret || !livekitUrl) {
    return json({ error: 'livekit-not-configured' }, 500);
  }

  const auth = req.headers.get('authorization') ?? '';
  const userJwt = auth.startsWith('Bearer ') ? auth.slice(7) : '';
  if (!userJwt) {
    return json({ error: 'unauthorized' }, 401);
  }

  // Per-request client with the caller's JWT so RLS applies.
  const supabaseUrl = Deno.env.get('SUPABASE_URL') ?? '';
  const supabaseAnonKey = Deno.env.get('SUPABASE_ANON_KEY') ?? '';
  const client = createClient(supabaseUrl, supabaseAnonKey, {
    global: { headers: { Authorization: auth } },
    auth: { persistSession: false, autoRefreshToken: false },
  });

  const { data: userRes, error: userErr } = await client.auth.getUser();
  if (userErr || !userRes.user) {
    return json({ error: 'unauthorized' }, 401);
  }
  const userId = userRes.user.id;

  const body = (await req.json().catch(() => ({}))) as RequestBody;
  const conversationId = body.conversationId?.trim();
  if (!conversationId) {
    return json({ error: 'conversation-id-required' }, 400);
  }

  // Membership check (RLS + explicit accepted flag).
  const { data: member, error: mErr } = await client
    .from('conversation_members')
    .select('user_id, accepted')
    .eq('conversation_id', conversationId)
    .eq('user_id', userId)
    .maybeSingle();
  if (mErr || !member || !member.accepted) {
    return json({ error: 'forbidden' }, 403);
  }

  const { data: profile } = await client
    .from('profiles')
    .select('username, display_name, banned')
    .eq('user_id', userId)
    .maybeSingle();
  if (profile?.banned) {
    return json({ error: 'banned' }, 403);
  }

  // LiveKit JWT — HS256 signed with API secret.
  const nowSec = Math.floor(Date.now() / 1000);
  const claims: Record<string, unknown> = {
    iss: apiKey,
    sub: userId,
    name: profile?.display_name ?? profile?.username ?? userId,
    nbf: nowSec,
    exp: nowSec + 60 * 10, // 10 min
    video: {
      room: conversationId,
      roomJoin: true,
      canPublish: true,
      canSubscribe: true,
      canPublishData: true,
    },
  };

  const secretBytes = new TextEncoder().encode(apiSecret);
  const token = await new SignJWT(claims as any)
    .setProtectedHeader({ alg: 'HS256', typ: 'JWT' })
    .sign(secretBytes);

  return json({
    token,
    url: livekitUrl,
    roomName: conversationId,
    identity: userId,
  });
});

function json(payload: unknown, status = 200): Response {
  return new Response(JSON.stringify(payload), {
    status,
    headers: { 'content-type': 'application/json', ...CORS_HEADERS },
  });
}
