import { starterRouteFetch } from "@/lib/wordpress-client";
import { getWordPressBaseUrl } from "@/lib/config";
import type {
  StorefrontCart,
  StorefrontCheckoutAddress,
  StorefrontCheckoutPaymentMethod,
  StorefrontCheckoutShippingPackage,
  StorefrontCheckoutState,
} from "@/types/storefront";
import {
  type StorefrontCartSession,
  getRawStorefrontCart,
  normalizeStorefrontCart,
} from "@/lib/storefront-cart";
import {
  fetchWooStoreJson,
  formatWooMoney,
} from "@/lib/woo-store-client";

interface WooAddress {
  first_name?: string;
  last_name?: string;
  address_1?: string;
  address_2?: string;
  city?: string;
  postcode?: string;
  country?: string;
  email?: string;
  phone?: string;
}

interface WooShippingRate {
  rate_id: string;
  name: string;
  description?: string;
  price: string;
  selected: boolean;
  currency_code: string;
  currency_minor_unit: number;
}

interface WooShippingPackage {
  package_id: number;
  name?: string;
  shipping_rates?: WooShippingRate[];
}

interface WooCart {
  billing_address?: WooAddress;
  shipping_address?: WooAddress;
  needs_payment: boolean;
  needs_shipping: boolean;
  shipping_rates?: WooShippingPackage[];
  payment_methods?: string[];
}

interface WooCheckout {
  billing_address?: WooAddress;
  shipping_address?: WooAddress;
  payment_method?: string;
}

interface WooCheckoutResult {
  order_id?: number;
  order_key?: string;
  status?: string;
  payment_result?: {
    redirect_url?: string;
    payment_status?: string;
  } | null;
}

interface PaymentMethodsResponse {
  items?: Array<{
    id?: string;
    label?: string;
  }>;
}

function buildLocalThankYouUrl(orderId: number | null | undefined, orderKey: string | null | undefined) {
  if (!orderId || !orderKey) {
    return null;
  }

  const params = new URLSearchParams({
    orderId: String(orderId),
    key: orderKey,
  });

  return `/checkout/thank-you?${params.toString()}`;
}

function normalizeCheckoutRedirectUrl(
  redirectUrl: string | null | undefined,
  orderId: number | null | undefined,
  orderKey: string | null | undefined,
) {
  const localThankYouUrl = buildLocalThankYouUrl(orderId, orderKey);

  if (!redirectUrl) {
    return localThankYouUrl;
  }

  try {
    const wordpressBaseUrl = new URL(getWordPressBaseUrl());
    const resolvedRedirectUrl = new URL(redirectUrl, wordpressBaseUrl);
    const isSameHost = resolvedRedirectUrl.origin === wordpressBaseUrl.origin;
    const isOrderReceivedPath = /\/order-received\/?/i.test(resolvedRedirectUrl.pathname);

    if (isSameHost && isOrderReceivedPath && localThankYouUrl) {
      return localThankYouUrl;
    }
  } catch {
    if (redirectUrl.includes("order-received") && localThankYouUrl) {
      return localThankYouUrl;
    }
  }

  return redirectUrl;
}

function normalizeAddress(address?: WooAddress): StorefrontCheckoutAddress {
  return {
    firstName: address?.first_name ?? "",
    lastName: address?.last_name ?? "",
    address1: address?.address_1 ?? "",
    address2: address?.address_2 ?? "",
    city: address?.city ?? "",
    postcode: address?.postcode ?? "",
    country: address?.country ?? "HR",
    email: address?.email ?? "",
    phone: address?.phone ?? "",
  };
}

function toWooAddress(address: StorefrontCheckoutAddress): WooAddress {
  return {
    first_name: address.firstName,
    last_name: address.lastName,
    address_1: address.address1,
    address_2: address.address2,
    city: address.city,
    postcode: address.postcode,
    country: address.country,
    email: address.email,
    phone: address.phone,
  };
}

function normalizePaymentMethodLabel(id: string) {
  return id
    .replace(/^wc-/, "")
    .replace(/[_-]+/g, " ")
    .replace(/\b\w/g, (character) => character.toUpperCase());
}

async function getPaymentMethodLabelMap() {
  try {
    const response = await starterRouteFetch<PaymentMethodsResponse>(
      "/payment-methods",
      { cache: "no-store" },
    );

    return new Map<string, string>(
      (response.items ?? [])
        .map((item) => {
          const id = item.id?.trim();
          const label = item.label?.trim();

          if (!id || !label) {
            return null;
          }

          return [id, label] as const;
        })
        .filter((entry): entry is readonly [string, string] => entry !== null),
    );
  } catch {
    return new Map<string, string>();
  }
}

async function requestStoreApiJson<T>(
  pathname: string,
  {
    method = "GET",
    session,
    body,
    retryOnAuthFailure = true,
  }: {
    method?: "GET" | "POST" | "PUT";
    session: StorefrontCartSession;
    body?: Record<string, unknown>;
    retryOnAuthFailure?: boolean;
  },
) {
  return fetchWooStoreJson<T>(pathname, {
    method,
    session,
    body,
    retryOnAuthFailure,
    refreshPath: "/cart",
  });
}

function normalizeShippingPackages(
  packages: WooShippingPackage[] | undefined,
): StorefrontCheckoutShippingPackage[] {
  return (packages ?? []).map((shippingPackage) => ({
    id: shippingPackage.package_id,
    label: shippingPackage.name || `Dostava ${shippingPackage.package_id + 1}`,
    rates: (shippingPackage.shipping_rates ?? []).map((rate) => ({
      id: rate.rate_id,
      label: rate.name,
      description: rate.description || undefined,
      price: formatWooMoney(rate.price, rate),
      selected: rate.selected,
    })),
  }));
}

function normalizePaymentMethods(
  paymentMethods: string[] | undefined,
  labelMap: Map<string, string>,
) {
  return (paymentMethods ?? []).map(
    (id): StorefrontCheckoutPaymentMethod => ({
      id,
      label: labelMap.get(id) || normalizePaymentMethodLabel(id),
    }),
  );
}

function toCheckoutState(
  cart: StorefrontCart,
  rawCart: WooCart,
  checkout: WooCheckout,
  paymentMethodLabelMap: Map<string, string>,
): StorefrontCheckoutState {
  return {
    cart,
    billingAddress: normalizeAddress(
      checkout.billing_address ?? rawCart.billing_address,
    ),
    shippingAddress: normalizeAddress(
      checkout.shipping_address ?? rawCart.shipping_address,
    ),
    shippingPackages: normalizeShippingPackages(rawCart.shipping_rates),
    paymentMethods: normalizePaymentMethods(
      rawCart.payment_methods,
      paymentMethodLabelMap,
    ),
    selectedPaymentMethod: checkout.payment_method || rawCart.payment_methods?.[0],
    needsShipping: rawCart.needs_shipping,
    needsPayment: rawCart.needs_payment,
  };
}

export async function getStorefrontCheckoutState(
  session: StorefrontCartSession,
) {
  const [cartResult, paymentMethodLabelMap] = await Promise.all([
    getRawStorefrontCart(session),
    getPaymentMethodLabelMap(),
  ]);
  const checkoutResult = await requestStoreApiJson<WooCheckout>("/checkout", {
    method: "GET",
    session: cartResult.session,
  });
  const normalizedCart = await normalizeStorefrontCart(cartResult.payload);

  return {
    checkout: toCheckoutState(
      normalizedCart,
      cartResult.payload as unknown as WooCart,
      checkoutResult.payload,
      paymentMethodLabelMap,
    ),
    session: checkoutResult.session,
  };
}

export async function updateStorefrontCheckout(
  session: StorefrontCartSession,
  input: {
    billingAddress: StorefrontCheckoutAddress;
    shippingAddress: StorefrontCheckoutAddress;
    paymentMethod: string;
    customerNote?: string;
    shippingSelection?: {
      packageId: number;
      rateId: string;
    };
  },
) {
  const paymentMethodLabelMap = await getPaymentMethodLabelMap();
  const updatedCart = await requestStoreApiJson<WooCart>("/cart/update-customer", {
    method: "POST",
    session,
    body: {
      billing_address: toWooAddress(input.billingAddress),
      shipping_address: toWooAddress(input.shippingAddress),
    },
  });

  let nextSession = updatedCart.session;

  if (input.shippingSelection?.rateId) {
    const shippingCart = await requestStoreApiJson<WooCart>(
      "/cart/select-shipping-rate",
      {
        method: "POST",
        session: updatedCart.session,
        body: {
          package_id: input.shippingSelection.packageId,
          rate_id: input.shippingSelection.rateId,
        },
      },
    );

    nextSession = shippingCart.session;
  }

  const checkoutResult = await requestStoreApiJson<WooCheckout>(
    "/checkout?__experimental_calc_totals=true",
    {
      method: "PUT",
      session: nextSession,
      body: {
        payment_method: input.paymentMethod,
        customer_note: input.customerNote || "",
      },
    },
  );
  const refreshedCart = await getRawStorefrontCart(checkoutResult.session);
  const normalizedCart = await normalizeStorefrontCart(refreshedCart.payload);

  return {
    checkout: toCheckoutState(
      normalizedCart,
      refreshedCart.payload as unknown as WooCart,
      checkoutResult.payload,
      paymentMethodLabelMap,
    ),
    session: refreshedCart.session,
  };
}

export async function submitStorefrontCheckoutOrder(
  session: StorefrontCartSession,
  input: {
    billingAddress: StorefrontCheckoutAddress;
    shippingAddress: StorefrontCheckoutAddress;
    paymentMethod: string;
    customerNote?: string;
    shippingSelection?: {
      packageId: number;
      rateId: string;
    };
  },
) {
  const updated = await updateStorefrontCheckout(session, input);
  const result = await requestStoreApiJson<WooCheckoutResult>("/checkout", {
    method: "POST",
    session: updated.session,
    body: {
      billing_address: toWooAddress(input.billingAddress),
      shipping_address: toWooAddress(input.shippingAddress),
      create_account: false,
      payment_method: input.paymentMethod,
      customer_note: input.customerNote || "",
    },
  });

  return {
    result: {
      orderId: result.payload.order_id ?? null,
      orderKey: result.payload.order_key ?? null,
      status: result.payload.status ?? null,
      redirectUrl: normalizeCheckoutRedirectUrl(
        result.payload.payment_result?.redirect_url ?? null,
        result.payload.order_id ?? null,
        result.payload.order_key ?? null,
      ),
      paymentStatus: result.payload.payment_result?.payment_status ?? null,
    },
    session: result.session,
  };
}
