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

export interface ProfileBrief {
  userId: string;
  username: string;
  displayName: string;
  avatarUrl: string | null;
  bannerUrl: string | null;
}

export type FriendDirection = 'outgoing' | 'incoming';

export interface Friendship {
  peer: ProfileBrief;
  status: FriendshipStatus;
  // Only meaningful when status === 'pending'.
  direction: FriendDirection;
  createdAt: string;
  acceptedAt: string | null;
}

const PROFILE_BRIEF_COLS = 'user_id, username, display_name, avatar_url, banner_url';

function mapProfileBrief(row: {
  user_id: string;
  username: string;
  display_name: string;
  avatar_url: string | null;
  banner_url: string | null;
}): ProfileBrief {
  return {
    userId: row.user_id,
    username: row.username,
    displayName: row.display_name,
    avatarUrl: row.avatar_url,
    bannerUrl: row.banner_url,
  };
}

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;
}

function pairKey(a: string, b: string): { lo: string; hi: string } {
  return a < b ? { lo: a, hi: b } : { lo: b, hi: a };
}

// ---------------------------------------------------------------------------
// Search
// ---------------------------------------------------------------------------

export async function searchProfiles(
  client: AppSupabaseClient,
  query: string,
  limit = 10,
): Promise<ProfileBrief[]> {
  const trimmed = query.trim();
  if (trimmed.length < 2) return [];
  const myId = await currentUserId(client);

  const { data, error } = await client
    .from('profiles')
    .select(PROFILE_BRIEF_COLS)
    .ilike('username', trimmed + '%')
    .neq('user_id', myId)
    .limit(limit);
  if (error) throw error;
  return (data ?? []).map(mapProfileBrief);
}

// ---------------------------------------------------------------------------
// Friendships list
// ---------------------------------------------------------------------------

export async function listFriendships(client: AppSupabaseClient): Promise<Friendship[]> {
  const myId = await currentUserId(client);

  const { data: rows, error } = await client
    .from('friendships')
    .select('user_lo, user_hi, status, requested_by, created_at, accepted_at')
    .order('created_at', { ascending: false });
  if (error) throw error;
  if (!rows || rows.length === 0) return [];

  const peerIds = Array.from(
    new Set(rows.map((r) => (r.user_lo === myId ? r.user_hi : r.user_lo))),
  );

  const { data: profiles, error: pErr } = await client
    .from('profiles')
    .select(PROFILE_BRIEF_COLS)
    .in('user_id', peerIds);
  if (pErr) throw pErr;

  const profileMap = new Map<string, ProfileBrief>();
  for (const p of profiles ?? []) {
    const brief = mapProfileBrief(p);
    profileMap.set(brief.userId, brief);
  }

  return rows.map<Friendship>((r) => {
    const peerId = r.user_lo === myId ? r.user_hi : r.user_lo;
    const peer = profileMap.get(peerId) ?? {
      userId: peerId,
      username: '?',
      displayName: '?',
      avatarUrl: null,
      bannerUrl: null,
    };
    return {
      peer,
      status: r.status,
      direction: r.requested_by === myId ? 'outgoing' : 'incoming',
      createdAt: r.created_at,
      acceptedAt: r.accepted_at,
    };
  });
}

// ---------------------------------------------------------------------------
// Mutations
// ---------------------------------------------------------------------------

export async function sendFriendRequest(
  client: AppSupabaseClient,
  targetUserId: string,
): Promise<void> {
  const { error } = await client.rpc('send_friend_request', { target_user_id: targetUserId });
  if (error) throw error;
}

export async function acceptFriendRequest(
  client: AppSupabaseClient,
  peerUserId: string,
): Promise<void> {
  const myId = await currentUserId(client);
  const { lo, hi } = pairKey(myId, peerUserId);
  const { error } = await client
    .from('friendships')
    .update({ status: 'accepted' })
    .eq('user_lo', lo)
    .eq('user_hi', hi);
  if (error) throw error;
}

// Used for both "decline incoming" and "cancel outgoing" — semantically a
// bilateral break.
export async function removeFriendship(
  client: AppSupabaseClient,
  peerUserId: string,
): Promise<void> {
  const myId = await currentUserId(client);
  const { lo, hi } = pairKey(myId, peerUserId);
  const { error } = await client
    .from('friendships')
    .delete()
    .eq('user_lo', lo)
    .eq('user_hi', hi);
  if (error) throw error;
}
