import { authClient } from '../auth-client';
import { fetchApi } from './client';
import type { User } from './types';

// Thin wrappers over the Better Auth client, preserving the legacy authApi
// call surface used by the auth pages.

type ClientError = { message?: string; code?: string; status: number } | null;

function throwIfError(error: ClientError, fallback: string): void {
  if (error) {
    const err = new Error(error.message || fallback);
    (err as any).code = error.code;
    (err as any).status = error.status;
    throw err;
  }
}

export const authApi = {
  // Magic link login. Enumeration-safe UX parity: unknown emails resolve with
  // the same generic message (magic links never create accounts server-side);
  // only rate limiting surfaces as an error.
  requestMagicLink: async (email: string, callbackURL: string = '/dashboard') => {
    const { error } = await authClient.signIn.magicLink({ email, callbackURL });
    if (error && error.status === 429) {
      throwIfError(error, 'Too many requests. Please try again later.');
    }
    return { message: 'If an account exists with this email, a login link has been sent.' };
  },

  verifyMagicLink: async (token: string) => {
    const { data, error } = await authClient.magicLink.verify({ query: { token } });
    throwIfError(error, 'Invalid or expired token');
    return data;
  },

  // Password reset (Better Auth is enumeration-safe here by default)
  requestPasswordReset: async (email: string) => {
    const { error } = await authClient.requestPasswordReset({
      email,
      redirectTo: '/auth/reset-password',
    });
    throwIfError(error, 'Failed to request password reset');
    return { message: 'If an account exists with this email, a password reset link has been sent.' };
  },

  confirmPasswordReset: async (token: string, password: string) => {
    const { error } = await authClient.resetPassword({ newPassword: password, token });
    throwIfError(error, 'Invalid or expired token');
    return { message: 'Password reset successfully. Please log in with your new password.' };
  },

  // Account claiming: a magic link that lands on the claim page, where the
  // session-holding user sets a password via /api/auth-ext/claim-account.
  requestClaimAccount: (email: string) =>
    authApi.requestMagicLink(email, '/auth/claim-account'),

  confirmClaimAccount: (password: string) =>
    fetchApi<{ user: User; message: string }>('/api/auth-ext/claim-account', {
      method: 'POST',
      body: JSON.stringify({ password }),
    }),

  claimEligibility: (email: string) =>
    fetchApi<{ canClaim: boolean }>(
      `/api/auth-ext/claim-eligibility?email=${encodeURIComponent(email)}`
    ),

  // Google Identity Services credential (ID token) sign-in
  googleAuth: async (credential: string) => {
    const { data, error } = await authClient.signIn.social({
      provider: 'google',
      idToken: { token: credential },
    });
    throwIfError(error, 'Google login failed');
    return data;
  },

  // Change password; other sessions are revoked so a stolen session can't
  // outlive the change (this device stays signed in).
  changePassword: async (currentPassword: string, newPassword: string) => {
    const { error } = await authClient.changePassword({
      currentPassword,
      newPassword,
      revokeOtherSessions: true,
    });
    throwIfError(error, 'Failed to change password');
    return { message: 'Password changed successfully' };
  },

  // Get current user
  me: async (): Promise<{ user: User | null }> => {
    const { data, error } = await authClient.getSession();
    throwIfError(error, 'Failed to load session');
    return { user: (data?.user as unknown as User) ?? null };
  },
};
