import type { AppSupabaseClient } from '../supabase/client.js';
import type { MemberRole } from '../supabase/types.js';

async function currentUserId(client: AppSupabaseClient): Promise<string> {
  const { data, error } = await client.auth.getUser();
  if (error) throw error;
  if (!data.user) throw new Error('not authenticated');
  return data.user.id;
}

export interface CreateGroupParams {
  client: AppSupabaseClient;
  name: string;
  memberUserIds: string[];
}

// Client-side 3-step create: conversation → self as admin → peers as members.
// On any peer-insert failure the conversation still survives (partial group is
// still usable, admin can retry). On self-insert failure we delete the empty
// conversation to avoid orphans.
export async function createGroup(params: CreateGroupParams): Promise<string> {
  const myId = await currentUserId(params.client);
  const trimmed = params.name.trim();
  if (trimmed.length === 0) throw new Error('group name required');

  // Generate the uuid client-side so we don't need a post-insert SELECT on
  // conversations — the SELECT policy requires membership, which only exists
  // AFTER we insert the creator's member row in step 2.
  const conversationId = crypto.randomUUID();

  const { error: cErr } = await params.client
    .from('conversations')
    .insert({
      id: conversationId,
      type: 'group',
      name: trimmed,
      created_by: myId,
    } as never);
  if (cErr) throw cErr;

  const { error: sErr } = await params.client.from('conversation_members').insert({
    conversation_id: conversationId,
    user_id: myId,
    role: 'admin',
    accepted: true,
  } as never);
  if (sErr) {
    await params.client.from('conversations').delete().eq('id', conversationId);
    throw sErr;
  }

  const peerIds = Array.from(new Set(params.memberUserIds)).filter((id) => id !== myId);
  if (peerIds.length > 0) {
    const rows = peerIds.map((user_id) => ({
      conversation_id: conversationId,
      user_id,
      role: 'member' as MemberRole,
      accepted: true,
    }));
    const { error: mErr } = await params.client
      .from('conversation_members')
      .insert(rows as never);
    if (mErr) throw mErr;
  }

  return conversationId;
}

// Add an accepted friend to a group. RLS allows the insert only when the
// caller is admin/mod of the conversation AND is friends with `userId`.
export async function addGroupMember(
  client: AppSupabaseClient,
  conversationId: string,
  userId: string,
): Promise<void> {
  const { error } = await client.from('conversation_members').insert({
    conversation_id: conversationId,
    user_id: userId,
    role: 'member',
    accepted: true,
  } as never);
  if (error) throw error;
}

export async function leaveGroup(
  client: AppSupabaseClient,
  conversationId: string,
): Promise<void> {
  const myId = await currentUserId(client);
  const { error } = await client
    .from('conversation_members')
    .delete()
    .eq('conversation_id', conversationId)
    .eq('user_id', myId);
  if (error) throw error;
}
