import type { UserRole } from '@/types';
import { getSupabaseClient } from '@/lib/supabase';

export interface DataAccessScope {
  userId: string | null;
  role: UserRole | null;
  isAdmin: boolean;
  accessToken: string | null;
}

type SessionUser = {
  id?: string | null;
};

type SessionData = {
  access_token?: string | null;
  user?: SessionUser | null;
};

type BatchVisibilityRow = {
  batch_id?: string | null;
};

async function getCurrentSessionData() {
  const supabase = getSupabaseClient();
  const authApi = (supabase as unknown as {
    auth?: {
      getSession?: () => Promise<{ data?: { session?: SessionData | null } | null; error?: unknown }>;
    };
  }).auth;

  if (!authApi?.getSession) {
    return null;
  }

  try {
    const result = await authApi.getSession();
    return result.data?.session ?? null;
  } catch {
    return null;
  }
}

async function getCurrentUserRole(userId: string): Promise<UserRole> {
  const supabase = getSupabaseClient();
  const { data, error } = await supabase
    .from('profiles')
    .select('role')
    .eq('id', userId)
    .maybeSingle();

  if (error) {
    return 'user';
  }

  return data?.role === 'admin' ? 'admin' : 'user';
}

export async function getCurrentAccessToken(): Promise<string | null> {
  return (await getCurrentSessionData())?.access_token ?? null;
}

export async function getCurrentDataAccessScope(): Promise<DataAccessScope> {
  const session = await getCurrentSessionData();
  const userId = session?.user?.id ?? null;

  if (!userId) {
    return {
      userId: null,
      role: null,
      isAdmin: false,
      accessToken: session?.access_token ?? null,
    };
  }

  const role = await getCurrentUserRole(userId);

  return {
    userId,
    role,
    isAdmin: role === 'admin',
    accessToken: session?.access_token ?? null,
  };
}

export async function getVisibleBatchIdsForScope(
  scope: DataAccessScope,
  options: { includeArchived?: boolean } = {},
): Promise<string[]> {
  if (!scope.userId) {
    return [];
  }

  const supabase = getSupabaseClient();
  let query = supabase
    .from('procurement_batches')
    .select('batch_id');

  if (!scope.isAdmin) {
    query = query.eq('created_by', scope.userId);
  }

  if (!options.includeArchived) {
    query = query.eq('archived', false);
  }

  const { data, error } = await query;
  if (error) {
    throw error;
  }

  return [...new Set(
    ((data ?? []) as BatchVisibilityRow[])
      .map((row) => String(row.batch_id ?? '').trim())
      .filter(Boolean),
  )];
}

export async function getVisibleBatchIds(options: { includeArchived?: boolean } = {}): Promise<string[]> {
  const scope = await getCurrentDataAccessScope();
  return getVisibleBatchIdsForScope(scope, options);
}