import { authClient } from '@/lib/api-client';
import { type PropsWithChildren, createContext, useContext, useMemo } from 'react';

export type User = typeof authClient.$Infer.Session.user;
export type Session = typeof authClient.$Infer.Session.session;

type SignInParams = {
  email: string;
  password: string;
};

type SignUpParams = {
  email: string;
  password: string;
  fullName: string;
  phone?: string;
};

type UpdateProfileParams = {
  fullName: string;
};

type UpdatePasswordParams = {
  currentPassword?: string;
  password: string;
};

export type AuthContextValue = {
  user: User | null;
  session: Session | null;
  loading: boolean;
  isAuthenticated: boolean;
  displayName: string;
  initials: string;
  avatarUrl: string | null;
  signInWithPassword: (params: SignInParams) => Promise<void>;
  signUp: (params: SignUpParams) => Promise<{ requiresEmailConfirmation: boolean }>;
  updateProfile: (params: UpdateProfileParams) => Promise<void>;
  updatePassword: (params: UpdatePasswordParams) => Promise<void>;
  signOut: () => Promise<void>;
};

const AuthContext = createContext<AuthContextValue | null>(null);

/**
 * Standard MD5 implementation for Gravatar support
 * (Self-contained to avoid dependency issues)
 */
function md5(string: string) {
  const k = Array.from({ length: 64 }, (_, i) => Math.floor(Math.abs(Math.sin(i + 1)) * 2 ** 32));
  let a = 0x67452301;
  let b = 0xefcdab89;
  let c = 0x98badcfe;
  let d = 0x10325476;
  const s = [
    7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9,
    14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21,
    6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21,
  ];

  const str = unescape(encodeURIComponent(string));
  const msg = new Uint8Array(str.length);
  for (let i = 0; i < str.length; i++) msg[i] = str.charCodeAt(i);

  const len = msg.length;
  const wordLen = ((len + 8) >> 6) + 1;
  const words = new Uint32Array(wordLen * 16);
  for (let i = 0; i < len; i++) words[i >> 2] |= msg[i] << ((i % 4) * 8);
  words[len >> 2] |= 0x80 << ((len % 4) * 8);
  words[wordLen * 16 - 2] = len * 8;

  for (let i = 0; i < words.length; i += 16) {
    const [aa, bb, cc, dd] = [a, b, c, d];
    for (let j = 0; j < 64; j++) {
      let f: number;
      let g: number;
      if (j < 16) {
        f = (b & c) | (~b & d);
        g = j;
      } else if (j < 32) {
        f = (d & b) | (~d & c);
        g = (5 * j + 1) % 16;
      } else if (j < 48) {
        f = b ^ c ^ d;
        g = (3 * j + 5) % 16;
      } else {
        f = c ^ (b | ~d);
        g = (7 * j) % 16;
      }
      const temp = d;
      d = c;
      c = b;
      b =
        (b +
          (((a + f + k[j] + words[i + g]) << s[j]) |
            ((a + f + k[j] + words[i + g]) >>> (32 - s[j])))) |
        0;
      a = temp;
    }
    a = (a + aa) | 0;
    b = (b + bb) | 0;
    c = (c + cc) | 0;
    d = (d + dd) | 0;
  }

  return [a, b, c, d]
    .map((v) =>
      Array.from({ length: 4 }, (_, i) =>
        ((v >> (i * 8)) & 0xff).toString(16).padStart(2, '0')
      ).join('')
    )
    .join('');
}

function getGravatarUrl(email: string): string {
  const hash = md5(email.trim().toLowerCase());
  return `https://www.gravatar.com/avatar/${hash}?d=identicon`;
}

function getDisplayName(user: User | null): string {
  if (!user) return 'Usuario';
  if (user.name?.trim()) return user.name.trim();
  return user.email ?? 'Usuario';
}

function getInitials(name: string): string {
  const words = name.trim().split(/\s+/).slice(0, 2);
  const initials = words.map((word) => word[0]?.toUpperCase() ?? '').join('');
  return initials || 'U';
}

function getAvatarUrl(user: User | null): string | null {
  if (!user) return null;
  return user.image || getGravatarUrl(user.email);
}

export function AuthProvider({ children }: PropsWithChildren) {
  const { data, isPending } = authClient.useSession();

  const user = data?.user ?? null;
  const session = data?.session ?? null;

  const value = useMemo<AuthContextValue>(() => {
    const displayName = getDisplayName(user);
    const initials = getInitials(displayName);
    const avatarUrl = getAvatarUrl(user);

    return {
      user,
      session,
      loading: isPending,
      isAuthenticated: Boolean(user),
      displayName,
      initials,
      avatarUrl,
      signInWithPassword: async ({ email, password }) => {
        const { error } = await authClient.signIn.email({
          email,
          password,
        });

        if (error) {
          throw error;
        }
      },
      signUp: async ({ email, password, fullName, phone }) => {
        const { data: signUpData, error } = await authClient.signUp.email({
          email,
          password,
          name: fullName,
          phone,
        });

        if (error) {
          throw error;
        }

        return {
          requiresEmailConfirmation: !signUpData || !('session' in signUpData),
        };
      },
      updateProfile: async ({ fullName }) => {
        const { error } = await authClient.updateUser({
          name: fullName,
        });

        if (error) {
          throw error;
        }
      },
      updatePassword: async ({ currentPassword, password }) => {
        // Better Auth uses changePassword for authenticated users
        const { error } = await authClient.changePassword({
          newPassword: password,
          currentPassword: currentPassword || '',
          revokeOtherSessions: true,
        });

        if (error) {
          throw error;
        }
      },
      signOut: async () => {
        const { error } = await authClient.signOut();
        if (error) {
          throw error;
        }
      },
    };
  }, [isPending, session, user]);

  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}

export function useAuth() {
  const context = useContext(AuthContext);

  if (!context) {
    throw new Error('useAuth must be used within AuthProvider');
  }

  return context;
}
