import Medusa from "@medusajs/js-sdk"

const MEDUSA_URL =
  process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL || "https://ot.azulado.cloud"
const PUBLISHABLE_KEY =
  process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY || ""

export const TOKEN_KEY = "ot_medusa_token"

export const sdk = new Medusa({
  baseUrl: MEDUSA_URL,
  publishableKey: PUBLISHABLE_KEY,
  auth: {
    type: "jwt",
    jwtTokenStorageMethod: "local",
    jwtTokenStorageKey: TOKEN_KEY,
  },
})

export type AuthCustomer = {
  id: string
  email: string
  first_name?: string | null
  last_name?: string | null
  metadata?: Record<string, unknown> | null
}

function errorMessage(error: unknown): string {
  if (error instanceof Error && error.message) return error.message
  if (typeof error === "object" && error && "message" in error) {
    const message = (error as { message?: unknown }).message
    if (typeof message === "string") return message
  }
  return ""
}

export const LOGIN_CREDENTIALS_ERROR =
  "Correo o clave de OLD TENNIS incorrectos."

export function isLoginCredentialsError(message: string) {
  const text = message.toLowerCase()
  return (
    text.includes("correo o clave de old tennis incorrectos") ||
    text.includes("invalid email or password") ||
    text.includes("no se pudo completar el acceso")
  )
}

export function friendlyAuthError(error: unknown, fallback: string) {
  const message = errorMessage(error).toLowerCase()
  if (message.includes("identity with email already exists")) {
    return "Este correo ya tiene una cuenta. Inicia sesión."
  }
  if (message.includes("invalid email or password")) {
    return LOGIN_CREDENTIALS_ERROR
  }
  if (
    message.includes("already has an account") ||
    message.includes("customer with this email")
  ) {
    return "Este correo ya tiene cuenta. Entra con Google o con la clave de OLD TENNIS."
  }
  if (message.includes("unauthorized")) {
    return LOGIN_CREDENTIALS_ERROR
  }
  return fallback
}

export async function registerWithEmail(input: {
  email: string
  password: string
  firstName: string
  lastName: string
}) {
  const email = input.email.trim().toLowerCase()
  let identityAlreadyExists = false

  try {
    await sdk.auth.register("customer", "emailpass", {
      email,
      password: input.password,
    })
  } catch (error: unknown) {
    const message = errorMessage(error)
    if (message !== "Identity with email already exists") {
      throw new Error(friendlyAuthError(error, "No se pudo crear la cuenta."))
    }
    identityAlreadyExists = true
    try {
      const login = await sdk.auth.login("customer", "emailpass", {
        email,
        password: input.password,
      })
      if (typeof login !== "string") {
        throw new Error("Este correo ya tiene una cuenta. Inicia sesión.")
      }
      const existing = await fetchCurrentCustomer()
      if (existing) return existing
    } catch {
      throw new Error("Este correo ya tiene una cuenta. Inicia sesión.")
    }
  }

  try {
    const { customer } = await sdk.store.customer.create({
      email,
      first_name: input.firstName.trim(),
      last_name: input.lastName.trim(),
    })

    await sdk.auth.login("customer", "emailpass", {
      email,
      password: input.password,
    })

    return customer
  } catch (error) {
    if (identityAlreadyExists) {
      const existing = await fetchCurrentCustomer()
      if (existing) return existing
    }
    throw new Error(friendlyAuthError(error, "No se pudo crear la cuenta."))
  }
}

export async function loginWithEmail(email: string, password: string) {
  try {
    const token = await sdk.auth.login("customer", "emailpass", {
      email: email.trim().toLowerCase(),
      password,
    })
    if (typeof token !== "string") {
      throw new Error("Este método de acceso requiere pasos adicionales.")
    }
    try {
      const { customer } = await sdk.store.customer.retrieve()
      return customer
    } catch {
      await sdk.auth.refresh()
      const { customer } = await sdk.store.customer.retrieve()
      return customer
    }
  } catch (error) {
    throw new Error(friendlyAuthError(error, "No se pudo iniciar sesión."))
  }
}

export async function startSocialLogin(provider: "google" | "apple") {
  const callbackUrl = `${
    process.env.NEXT_PUBLIC_SITE_URL || "https://ot.azulado.cloud"
  }/account/callback/${provider}`

  const result = await sdk.auth.login("customer", provider, {
    callback_url: callbackUrl,
  })

  if (typeof result === "object" && result && "location" in result && result.location) {
    window.location.href = result.location as string
    return
  }

  if (typeof result === "string") {
    const { customer } = await sdk.store.customer.retrieve()
    return customer
  }

  throw new Error(`No se pudo iniciar sesión con ${provider}.`)
}

export async function completeSocialCallback(provider: "google" | "apple") {
  const token = await sdk.auth.callback(
    "customer",
    provider,
    Object.fromEntries(new URLSearchParams(window.location.search))
  )

  if (!token || typeof token !== "string") {
    throw new Error("Callback de autenticación inválido.")
  }

  const payload = JSON.parse(
    atob(token.split(".")[1].replace(/-/g, "+").replace(/_/g, "/"))
  ) as {
    actor_id?: string
    user_metadata?: { email?: string; name?: string }
  }

  const shouldCreateCustomer = !payload.actor_id
  const email = payload.user_metadata?.email

  if (shouldCreateCustomer) {
    if (!email) {
      throw new Error(
        "No recibimos el email del proveedor. Revisa el consentimiento OAuth."
      )
    }
    const name = payload.user_metadata?.name || ""
    const [firstName, ...rest] = name.split(" ")
    await sdk.store.customer.create({
      email,
      first_name: firstName || undefined,
      last_name: rest.join(" ") || undefined,
    })
    await sdk.auth.refresh()
  }

  const { customer } = await sdk.store.customer.retrieve()
  return customer
}

export async function requestPasswordReset(email: string) {
  await sdk.auth.resetPassword("customer", "emailpass", {
    identifier: email.trim().toLowerCase(),
  })
}

export async function updatePasswordWithToken(input: {
  email: string
  password: string
  token: string
}) {
  const token = input.token.replace(/\s+/g, "")
  const res = await fetch(`${MEDUSA_URL}/auth/customer/emailpass/update`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      accept: "application/json",
      Authorization: `Bearer ${token}`,
      ...(PUBLISHABLE_KEY ? { "x-publishable-api-key": PUBLISHABLE_KEY } : {}),
    },
    body: JSON.stringify({
      email: input.email.trim().toLowerCase(),
      password: input.password,
    }),
  })
  if (!res.ok) {
    const data = (await res.json().catch(() => ({}))) as { message?: string }
    throw new Error(data.message || "Invalid token")
  }
}

export async function logout() {
  try {
    await sdk.auth.logout()
  } catch {
    // Si Medusa falla, igual cerramos la sesión local.
  }
  if (typeof window !== "undefined") {
    window.localStorage.removeItem(TOKEN_KEY)
    window.sessionStorage.removeItem(TOKEN_KEY)
  }
}

export async function fetchCurrentCustomer(): Promise<AuthCustomer | null> {
  try {
    const { customer } = await sdk.store.customer.retrieve({
      fields: "+metadata",
    })
    return customer as AuthCustomer
  } catch {
    return null
  }
}

export async function updateCustomerProfile(input: {
  firstName: string
  lastName: string
}) {
  try {
    const { customer } = await sdk.store.customer.update({
      first_name: input.firstName.trim(),
      last_name: input.lastName.trim(),
    })
    return customer as AuthCustomer
  } catch (error) {
    throw new Error(
      friendlyAuthError(error, "No se pudo actualizar tu información.")
    )
  }
}

export async function syncCustomerFavorites(
  favorites: { id: string; slug: string; name: string; price: number; image: string; collection: string }[]
) {
  try {
    await sdk.store.customer.update({
      metadata: { ot_favorites: favorites },
    })
  } catch {
    /* silent — localStorage sigue siendo fuente local */
  }
}
