import { getAuthToken } from "./auth-token";

type AnyObject = Record<string, any>;

/*
|--------------------------------------------------------------------------
| Shared Request Helper
|--------------------------------------------------------------------------
*/

async function walletFetch(url: string, init: RequestInit) {
  const token = getAuthToken();

  if (!token) {
    return {
      authenticated: false,
      success: false,
      data: null,
      message: "Please login first.",
    };
  }

  try {
    const response = await fetch(url, {
      ...init,

      headers: {
        ...(init.headers || {}),
        Authorization: `Bearer ${token}`,
      },

      cache: "no-store",
    });

    const result = await response.json();

    if (response.status === 401) {
      return {
        authenticated: false,
        success: false,
        data: null,
        message: result?.message || "Authentication expired.",
      };
    }

    if (!response.ok || result?.status === false || result?.success === false) {
      return {
        authenticated: true,
        success: false,
        data: null,
        message: result?.message || "Wallet request failed.",
      };
    }

    return {
      authenticated: true,
      success: true,
      data: result.data ?? result,
      message: result.message,
    };
  } catch (error) {
    console.error("Wallet request error:", error);

    return {
      authenticated: true,
      success: false,
      data: null,
      message: "Unable to connect to the wallet API.",
    };
  }
}

/*
|--------------------------------------------------------------------------
| Wallet Offers (recharge price list)
|--------------------------------------------------------------------------
*/

export async function getWalletOffers() {
  return walletFetch("/api/wallet/offers", { method: "GET" });
}

/*
|--------------------------------------------------------------------------
| Wallet Transactions
|--------------------------------------------------------------------------
|
| Confirmed live: POST /user/wallet/transactions (a GET 404s — same
| "reads like a GET, is actually a POST" mislabeling seen elsewhere in
| this codebase). {page, limit} is all it needs; a transactionType/type
| filter in the body is a no-op (confirmed live, same result either
| way), so per-tab filtering happens client-side via
| categorizeWalletTransaction() below.
|
*/

export interface WalletTransaction {
  id: number;
  title: string;
  transactionNumber: string;
  transactionType: string;
  amount: number;
  isCredit: boolean;
  icon: string;
  createdAt: string;
  astrologerName?: string;
}

export async function getWalletTransactions(page = 1, limit = 100) {
  return walletFetch("/api/wallet/transactions", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ page, limit }),
  });
}

/*
|--------------------------------------------------------------------------
| Wallet Transaction Details (single row, drill-down)
|--------------------------------------------------------------------------
|
| Confirmed live: POST /user/wallet/transaction/details, a separate
| endpoint from the list above despite the similar path. Takes
| {id, transactionType} — both required, and transactionType must be
| the exact string the list row had (CHAT/CALL/ORDER/RECHARGE/etc; it
| picks which backend table gets searched). Only CHAT was verified
| against a row this app's own test account actually owns (real
| astrologer + session data came back); CALL/ORDER/RECHARGE are wired
| to the same documented shape but weren't reachable with a real id
| this account owns.
|
*/

export interface WalletTransactionDetails {
  id: number;
  title: string;
  transactionNumber: string;
  transactionType: string;
  amount: number;
  isCredit: boolean;
  status: string;
  icon: string;
  createdAt: string;
  astrologer: { id: number; name: string; profileImage?: string } | null;
  session: { sessionType: string; status: string; durationSeconds: number } | null;
  payment: {
    paymentMode?: string;
    paymentReference?: string;
    orderId?: string;
    paymentStatus?: string;
    cashbackAmount?: number;
  } | null;
  product: {
    id: number;
    name: string;
    productImage?: string;
    price?: number;
    sellingPrice?: number;
  } | null;
  address: {
    name?: string;
    phoneNumber?: string;
    flatNo?: string;
    locality?: string;
    landmark?: string;
    city?: string;
    state?: string;
    country?: string;
    pincode?: string;
  } | null;
}

export async function getWalletTransactionDetails(id: number, transactionType: string) {
  return walletFetch("/api/wallet/transaction/details", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ id, transactionType }),
  });
}

export type WalletTransactionCategory = "call" | "chat" | "payment" | "wallet";

// "Payment Logs" = add-money/recharge (isCredit — money coming in);
// "Call"/"Chat" = that medium's consultation debits (transactionType
// CALL/CHAT, or a DEMO_ variant of either — confirmed live for
// DEMO_CHAT); "Wallet Transactions" is the honest catch-all for
// everything else (e.g. HoroscopeView) that isn't a call, a chat, or a
// recharge.
export function categorizeWalletTransaction(
  tx: WalletTransaction,
): WalletTransactionCategory {
  if (tx.isCredit) return "payment";

  const type = String(tx.transactionType || "").toUpperCase();

  if (type.includes("CALL")) return "call";
  if (type.includes("CHAT")) return "chat";

  return "wallet";
}

/*
|--------------------------------------------------------------------------
| Create Payment Order
|--------------------------------------------------------------------------
*/

export interface CreateOrderPayload {
  amount: number;
  platform?: string;
  paymentMode?: string;
}

export async function createWalletOrder(payload: CreateOrderPayload) {
  return walletFetch("/api/wallet/create-order", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      platform: "web",
      paymentMode: "PHONEPE",
      ...payload,
    }),
  });
}

/*
|--------------------------------------------------------------------------
| Parsing — Wallet Balance
|--------------------------------------------------------------------------
|
| Confirmed live: GET /user/profile's real field is the nested
| `UserWallet.amount` (e.g. {"UserWallet":{"id":192,"userId":204,
| "amount":0}}) — not a flat top-level field. Check that first, then
| fall back to the flat aliases in case a different endpoint's user
| object shapes this differently.
|
*/

const BALANCE_FIELD_ALIASES = [
  "Wallet",
  "WalletBalance",
  "WalletAmount",
  "Balance",
  "wallet",
  "walletBalance",
  "wallet_balance",
  "balance",
];

export function getWalletBalance(user: AnyObject | null): number {
  if (!user) {
    return 0;
  }

  const nested = user.UserWallet?.amount ?? user.userWallet?.amount ?? user.user_wallet?.amount;

  if (typeof nested === "number" && !Number.isNaN(nested)) {
    return nested;
  }

  if (typeof nested === "string" && nested.trim() && !Number.isNaN(Number(nested))) {
    return Number(nested);
  }

  for (const key of BALANCE_FIELD_ALIASES) {
    const value = user[key];

    if (typeof value === "number" && !Number.isNaN(value)) {
      return value;
    }

    if (typeof value === "string" && value.trim() && !Number.isNaN(Number(value))) {
      return Number(value);
    }
  }

  return 0;
}

/*
|--------------------------------------------------------------------------
| Parsing — Wallet Offers (price list)
|--------------------------------------------------------------------------
*/

export interface WalletOffer {
  id: string;
  amount: number;
  bonus?: number;
  label?: string;
  isPopular?: boolean;
}

export function parseWalletOffers(raw: any): WalletOffer[] {
  const report = unwrapUntil(raw);

  const list: any[] = Array.isArray(report)
    ? report
    : Array.isArray(report?.offers)
      ? report.offers
      : Array.isArray(report?.list)
        ? report.list
        : Array.isArray(report?.plans)
          ? report.plans
          : [];

  return list
    .map((item, index) => {
      const amount = firstNumber(item, ["amount", "price", "value", "rechargeAmount"]);

      if (amount === null) {
        return null;
      }

      const bonus = firstNumber(item, ["bonus", "extra", "cashback", "bonusAmount"]);

      const label = firstString(item, ["label", "title", "name", "tag"]);

      const isPopular = Boolean(
        item?.isPopular ?? item?.popular ?? item?.is_popular ?? item?.recommended,
      );

      return {
        id: String(item?.id ?? item?._id ?? amount ?? index),
        amount,
        bonus: bonus ?? undefined,
        label,
        isPopular,
      };
    })
    .filter(Boolean) as WalletOffer[];
}

function unwrapUntil(raw: any): AnyObject {
  if (!raw || typeof raw !== "object") {
    return {};
  }

  let current: AnyObject = raw;

  let guard = 0;

  while (
    current &&
    typeof current === "object" &&
    !Array.isArray(current) &&
    !("offers" in current || "list" in current || "plans" in current) &&
    current.data &&
    typeof current.data === "object" &&
    guard < 5
  ) {
    current = current.data;
    guard++;
  }

  return current;
}

function firstNumber(obj: AnyObject, aliases: string[]): number | null {
  for (const key of aliases) {
    const value = obj?.[key];

    if (typeof value === "number" && !Number.isNaN(value)) {
      return value;
    }

    if (typeof value === "string" && value.trim() && !Number.isNaN(Number(value))) {
      return Number(value);
    }
  }

  return null;
}

function firstString(obj: AnyObject, aliases: string[]): string | undefined {
  for (const key of aliases) {
    const value = obj?.[key];

    if (typeof value === "string" && value.trim()) {
      return value.trim();
    }
  }

  return undefined;
}

/*
|--------------------------------------------------------------------------
| Parsing — Payment Order Redirect
|--------------------------------------------------------------------------
*/

export function extractPaymentRedirectUrl(raw: any): string | undefined {
  const report = unwrapUntil(raw);

  return firstString(report, [
    "redirectUrl",
    "paymentUrl",
    "url",
    "checkoutUrl",
    "redirect_url",
    "payment_url",
  ]);
}

/*
|--------------------------------------------------------------------------
| Default price list (used if the API returns nothing usable)
|--------------------------------------------------------------------------
*/

export const DEFAULT_WALLET_OFFERS: WalletOffer[] = [
  { id: "100", amount: 100 },
  { id: "200", amount: 200 },
  { id: "500", amount: 500, isPopular: true },
  { id: "1000", amount: 1000 },
  { id: "2000", amount: 2000 },
  { id: "5000", amount: 5000 },
];
