import type { SupportedLocale } from '../i18n/types.js';
import type { AppSupabaseClient } from '../supabase/client.js';
import type { Database, PresenceState } from '../supabase/types.js';

type ProfileUpdate = Database['public']['Tables']['profiles']['Update'];

export interface Profile {
  userId: string;
  username: string;
  displayName: string;
  avatarUrl: string | null;
  bannerUrl: string | null;
  statusMessage: string | null;
  presenceState: PresenceState;
  showReadReceipts: boolean;
  allowDmsFromStrangers: boolean;
  isAdmin: boolean;
  locale: SupportedLocale;
}

type ProfileRow = {
  user_id: string;
  username: string;
  display_name: string;
  avatar_url: string | null;
  banner_url: string | null;
  status_message: string | null;
  presence_state: PresenceState;
  show_read_receipts: boolean;
  allow_dms_from_strangers: boolean;
  is_admin: boolean;
  locale: string;
};

const PROFILE_COLS =
  'user_id, username, display_name, avatar_url, banner_url, status_message, presence_state, show_read_receipts, allow_dms_from_strangers, is_admin, locale';

function toSupportedLocale(raw: string): SupportedLocale {
  return raw === 'de' ? 'de' : 'en';
}

function mapProfile(row: ProfileRow): Profile {
  return {
    userId: row.user_id,
    username: row.username,
    displayName: row.display_name,
    avatarUrl: row.avatar_url,
    bannerUrl: row.banner_url,
    statusMessage: row.status_message,
    presenceState: row.presence_state,
    showReadReceipts: row.show_read_receipts,
    allowDmsFromStrangers: row.allow_dms_from_strangers,
    isAdmin: row.is_admin,
    locale: toSupportedLocale(row.locale),
  };
}

export async function getOwnProfile(client: AppSupabaseClient): Promise<Profile | null> {
  const { data: session } = await client.auth.getUser();
  if (!session.user) return null;

  const { data, error } = await client
    .from('profiles')
    .select(PROFILE_COLS)
    .eq('user_id', session.user.id)
    .maybeSingle();
  if (error) throw error;
  return data ? mapProfile(data as unknown as ProfileRow) : null;
}

export async function getProfileByUsername(
  client: AppSupabaseClient,
  username: string,
): Promise<Profile | null> {
  const { data, error } = await client
    .from('profiles')
    .select(PROFILE_COLS)
    // citext column compares CI server-side — send raw input, don't force case.
    .eq('username', username.trim())
    .maybeSingle();
  if (error) throw error;
  return data ? mapProfile(data as unknown as ProfileRow) : null;
}

export async function isUsernameAvailable(
  client: AppSupabaseClient,
  username: string,
): Promise<boolean> {
  const { count, error } = await client
    .from('profiles')
    .select('user_id', { count: 'exact', head: true })
    // citext compares CI — no manual normalization needed.
    .eq('username', username.trim());
  if (error) throw error;
  return (count ?? 0) === 0;
}

export interface UpdateProfileParams {
  displayName?: string;
  avatarUrl?: string | null;
  bannerUrl?: string | null;
  statusMessage?: string | null;
  presenceState?: PresenceState;
  showReadReceipts?: boolean;
  allowDmsFromStrangers?: boolean;
  locale?: SupportedLocale;
}

export async function updateOwnProfile(
  client: AppSupabaseClient,
  params: UpdateProfileParams,
): Promise<Profile> {
  const { data: session } = await client.auth.getUser();
  if (!session.user) throw new Error('not authenticated');

  const patch: ProfileUpdate = {};
  if (params.displayName !== undefined) patch.display_name = params.displayName;
  if (params.avatarUrl !== undefined) patch.avatar_url = params.avatarUrl;
  if (params.bannerUrl !== undefined) patch.banner_url = params.bannerUrl;
  if (params.statusMessage !== undefined) patch.status_message = params.statusMessage;
  if (params.presenceState !== undefined) patch.presence_state = params.presenceState;
  if (params.showReadReceipts !== undefined) patch.show_read_receipts = params.showReadReceipts;
  if (params.allowDmsFromStrangers !== undefined) {
    patch.allow_dms_from_strangers = params.allowDmsFromStrangers;
  }
  if (params.locale !== undefined) {
    (patch as ProfileUpdate & { locale?: string }).locale = params.locale;
  }

  const { data, error } = await client
    .from('profiles')
    .update(patch)
    .eq('user_id', session.user.id)
    .select(PROFILE_COLS)
    .single();
  if (error) throw error;
  return mapProfile(data as unknown as ProfileRow);
}
