"use server";

import { cookies } from "next/headers";
import { HttpTypes } from "@medusajs/types";
import { medusa, medusaHeaders } from "@/lib/medusa/client";
import { env } from "@/lib/env";
import { getDefaultRegion } from "@/lib/medusa/regions";
import { MondialRelayPoint, getMondialRelayPointFromCart, upsertMondialRelayPointMetadata } from "@/lib/mondial-relay";
import { isLocalPickupShippingOption } from "@/lib/local-pickup";
import { getCustomizationSurchargePerUnitCents } from "@/lib/personalization-pricing";

const CART_COOKIE = "stylunique_cart_id";
const CART_FIELDS_PRIMARY =
  "*items,*items.variant,*items.product,*promotions,*discounts,*shipping_methods,*shipping_methods.shipping_option,+items.total,+total,+subtotal,+tax_total,+shipping_total,+discount_total,+metadata,*region,*shipping_address";
const CART_FIELDS_FALLBACK =
  "*items,*items.variant,*items.product,*shipping_methods,+items.total,+total,+subtotal,+tax_total,+shipping_total,+discount_total,+metadata,*region,*shipping_address";

async function getCartId() {
  const cookieStore = await cookies();
  return cookieStore.get(CART_COOKIE)?.value;
}

export async function clearCartCookie() {
  const cookieStore = await cookies();
  cookieStore.delete(CART_COOKIE);
}

async function setCartId(cartId: string) {
  const cookieStore = await cookies();
  cookieStore.set(CART_COOKIE, cartId, {
    httpOnly: true,
    sameSite: "lax",
    secure: process.env.NODE_ENV === "production",
    path: "/",
    maxAge: 60 * 60 * 24 * 30,
  });
}

async function updateCartMetadata(cartId: string, metadata: Record<string, unknown>) {
  await medusa.client.fetch(`/store/carts/${cartId}`, {
    method: "POST",
    body: { metadata },
    headers: medusaHeaders(),
    cache: "no-store",
  });
}

async function clearQuotePricingLock(cartId: string) {
  const cart = await fetchCartById(cartId, medusaHeaders());
  const currentMetadata = (cart as { metadata?: Record<string, unknown> | null } | null)?.metadata || {};

  if (!("quote_pricing" in currentMetadata)) {
    return;
  }

  const nextMetadata = { ...currentMetadata };
  delete nextMetadata.quote_pricing;
  await updateCartMetadata(cartId, nextMetadata);
}

async function fetchCartById(cartId: string, headers: Record<string, string>) {
  try {
    const response = await medusa.client.fetch<{ cart: HttpTypes.StoreCart }>(`/store/carts/${cartId}`, {
      method: "GET",
      query: {
        fields: CART_FIELDS_PRIMARY,
      },
      headers,
      cache: "no-store",
    });
    return response.cart || null;
  } catch {
    // Fallback for Medusa setups that don't support all expanded fields.
    try {
      const fallback = await medusa.client.fetch<{ cart: HttpTypes.StoreCart }>(`/store/carts/${cartId}`, {
        method: "GET",
        query: {
          fields: CART_FIELDS_FALLBACK,
        },
        headers,
        cache: "no-store",
      });
      return fallback.cart || null;
    } catch {
      return null;
    }
  }
}

function cartHasShippingMethod(cart: HttpTypes.StoreCart) {
  const shippingMethods = (cart as { shipping_methods?: unknown[] }).shipping_methods;
  return Array.isArray(shippingMethods) && shippingMethods.length > 0;
}

function cartIsCompleted(cart: HttpTypes.StoreCart) {
  const maybeCompletedAt = (cart as { completed_at?: string | null; completedAt?: string | null });
  return Boolean(maybeCompletedAt.completed_at || maybeCompletedAt.completedAt);
}

export type StoreShippingOption = {
  id?: string;
  name?: string | null;
  amount?: number | null;
  provider_id?: string | null;
  data?: Record<string, unknown> | null;
};

const MONDIAL_RELAY_HINTS = ["mondial", "relay", "point relais", "locker"];

function parseConfiguredMondialRelayOptionIds() {
  return new Set(
    env.mondialRelayShippingOptionIds
      .split(",")
      .map((value) => value.trim())
      .filter(Boolean),
  );
}

function isMondialRelayOption(option: StoreShippingOption | undefined, optionId: string) {
  const configuredIds = parseConfiguredMondialRelayOptionIds();
  if (configuredIds.has(optionId)) {
    return true;
  }

  const labels = [option?.name, option?.provider_id, String(option?.data?.id || "")]
    .map((value) => String(value || "").toLowerCase())
    .filter(Boolean);

  return labels.some((value) => MONDIAL_RELAY_HINTS.some((hint) => value.includes(hint)));
}

function asPositiveNumber(value: unknown) {
  const parsed = Number(value);
  return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
}

function getDefaultItemWeight() {
  return asPositiveNumber(env.mondialRelayDefaultItemWeight) ?? 100;
}

function toWeightGrams(weight: number) {
  return env.mondialRelayWeightUnit.trim().toLowerCase() === "kg"
    ? weight * 1000
    : weight;
}

function getCartTotalWeightGrams(cart: HttpTypes.StoreCart) {
  const items = (cart.items || []) as Array<{
    quantity?: number | null;
    variant?: { weight?: number | string | null } | null;
    product?: { weight?: number | string | null } | null;
  }>;

  const total = items.reduce((sum, item) => {
    const quantity = Math.max(1, Number(item.quantity || 1));
    const rawWeight = asPositiveNumber(item.variant?.weight) ?? asPositiveNumber(item.product?.weight) ?? getDefaultItemWeight();
    return sum + toWeightGrams(rawWeight) * quantity;
  }, 0);

  return Math.max(1, Math.round(total));
}

function buildMondialRelayShippingData(cart: HttpTypes.StoreCart, option: StoreShippingOption | undefined) {
  const point = getMondialRelayPointFromCart(cart);
  const data: Record<string, unknown> = {
    shipping_option_name: option?.name || "Mondial Relay - Point Relais",
    total_weight: getCartTotalWeightGrams(cart),
    cart_total: typeof cart.total === "number" ? cart.total / 100 : undefined,
    metadata: {
      id: "mondialrelay-point-relais",
      type: "relay",
    },
  };

  if (point) {
    data.parcel_shop_id = point.id;
    data.parcel_shop_name = point.name;
    data.parcel_shop_address = point.address1;
    data.parcel_shop_city = point.city;
    data.parcel_shop_postcode = normalizePostalCode(point.postalCode);
    data.parcel_shop_country_code = point.countryCode.toUpperCase();
  }

  return data;
}

async function listShippingOptionsForCart(cartId: string, headers: Record<string, string>) {
  try {
    const response = await medusa.client.fetch<{ shipping_options?: StoreShippingOption[] }>("/store/shipping-options", {
      method: "GET",
      query: { cart_id: cartId },
      headers,
      cache: "no-store",
    });
    return Array.isArray(response.shipping_options) ? response.shipping_options : [];
  } catch {
    return [];
  }
}

export async function getCartShippingOptions() {
  const cart = await getCart();
  if (!cart) {
    return [];
  }

  return listShippingOptionsForCart(cart.id, medusaHeaders());
}

function selectDefaultShippingOptionId(options: StoreShippingOption[]) {
  const candidates = options
    .filter((option): option is StoreShippingOption & { id: string } => typeof option.id === "string" && option.id.length > 0)
    .map((option) => {
      const name = (option.name || "").toLowerCase();
      const isStandard = name.includes("standard");
      const isLocalPickup = isLocalPickupShippingOption(option);
      const amount = typeof option.amount === "number" ? option.amount : Number.MAX_SAFE_INTEGER;
      return { id: option.id, isStandard, isLocalPickup, amount };
    });

  if (!candidates.length) {
    return null;
  }

  candidates.sort((a, b) => {
    if (a.isLocalPickup !== b.isLocalPickup) {
      return a.isLocalPickup ? 1 : -1;
    }
    if (a.isStandard !== b.isStandard) {
      return a.isStandard ? -1 : 1;
    }
    return a.amount - b.amount;
  });

  return candidates[0].id;
}

async function ensureCartHasShippingMethod(cart: HttpTypes.StoreCart, headers: Record<string, string>) {
  if (cartHasShippingMethod(cart)) {
    return cart;
  }

  const options = await listShippingOptionsForCart(cart.id, headers);
  const defaultOptionId = selectDefaultShippingOptionId(options);

  if (!defaultOptionId) {
    return cart;
  }

  try {
    await medusa.client.fetch(`/store/carts/${cart.id}/shipping-methods`, {
      method: "POST",
      body: { option_id: defaultOptionId },
      headers,
      cache: "no-store",
    });
    return (await fetchCartById(cart.id, headers)) || cart;
  } catch {
    return cart;
  }
}

export async function getCart(): Promise<HttpTypes.StoreCart | null> {
  const cartId = await getCartId();
  if (!cartId) {
    return null;
  }

  const headers = medusaHeaders();
  const cart = await fetchCartById(cartId, headers);
  if (!cart) {
    return null;
  }

  if (cartIsCompleted(cart)) {
    return null;
  }

  return ensureCartHasShippingMethod(cart, headers);
}

export async function getOrCreateCart(): Promise<HttpTypes.StoreCart> {
  const existing = await getCart();
  if (existing) {
    return existing;
  }

  const region = await getDefaultRegion();
  if (!region) {
    throw new Error("No region configured in Medusa. Run the seed script first.");
  }

  const response = await medusa.store.cart.create({ region_id: region.id }, {}, medusaHeaders());
  await setCartId(response.cart.id);
  return response.cart;
}

export async function addToCart(input: {
  variantId: string;
  quantity: number;
  personalization?: string;
  theme?: string;
  paperFinish?: string;
  customizations?: Record<string, { label?: string; value?: string; priceCents?: number }>;
}) {
  const cart = await getOrCreateCart();

  const metadata: Record<string, unknown> = {};
  if (input.personalization?.trim()) {
    metadata.personalization = input.personalization.trim();
  }
  if (input.theme?.trim()) {
    metadata.theme = input.theme.trim();
  }
  if (input.paperFinish?.trim()) {
    metadata.paper_finish = input.paperFinish.trim();
  }
  if (input.customizations) {
    const customizations = Object.fromEntries(
      Object.entries(input.customizations)
        .map(([key, value]) => {
          const label = typeof value?.label === "string" ? value.label.trim() : "";
          const entryValue = typeof value?.value === "string" ? value.value.trim() : "";
          const priceCents = typeof value?.priceCents === "number" && Number.isFinite(value.priceCents) ? Math.max(0, Math.round(value.priceCents)) : undefined;
          return [key, label && entryValue ? { label, value: entryValue, ...(typeof priceCents === "number" ? { priceCents } : {}) } : null];
        })
        .filter(([, value]) => Boolean(value)),
    );

    if (Object.keys(customizations).length) {
      metadata.customizations = customizations;
      const customizationSurchargeCents = getCustomizationSurchargePerUnitCents(customizations);
      if (customizationSurchargeCents > 0) {
        metadata.customization_surcharge_cents = customizationSurchargeCents;
      }
    }
  }
  await medusa.store.cart.createLineItem(
    cart.id,
    {
      variant_id: input.variantId,
      quantity: input.quantity,
      metadata: Object.keys(metadata).length ? metadata : undefined,
    },
    {},
    medusaHeaders(),
  );
  await clearQuotePricingLock(cart.id);
}

export async function updateCartEventDate(eventDate: string | null) {
  const cart = await getCart();
  if (!cart) {
    return { ok: false, message: "Aucun panier actif." } as const;
  }

  const normalizedDate = (eventDate || "").trim();
  if (normalizedDate && !/^\d{4}-\d{2}-\d{2}$/.test(normalizedDate)) {
    return { ok: false, message: "Date d'événement invalide." } as const;
  }

  const existingMetadata = (cart as { metadata?: Record<string, unknown> | null }).metadata;
  const nextMetadata: Record<string, unknown> = { ...(existingMetadata || {}) };

  if (normalizedDate) {
    nextMetadata.event_date = normalizedDate;
  } else {
    delete nextMetadata.event_date;
  }

  try {
    await medusa.client.fetch(`/store/carts/${cart.id}`, {
      method: "POST",
      body: {
        metadata: nextMetadata,
      },
      headers: medusaHeaders(),
      cache: "no-store",
    });

    return {
      ok: true,
      message: normalizedDate ? "Date de l'événement enregistrée." : "Date de l'événement supprimée.",
    } as const;
  } catch (error) {
    const message =
      error instanceof Error && error.message
        ? error.message
        : "Impossible de mettre à jour la date de l'événement.";
    return { ok: false, message } as const;
  }
}

export async function updateCartOrderNote(orderNote: string | null) {
  const cart = await getCart();
  if (!cart) {
    return { ok: false, message: "Aucun panier actif." } as const;
  }

  const normalizedNote = (orderNote || "").trim();
  if (normalizedNote.length > 1000) {
    return { ok: false, message: "La note ne peut pas dépasser 1000 caractères." } as const;
  }

  const existingMetadata = (cart as { metadata?: Record<string, unknown> | null }).metadata;
  const nextMetadata: Record<string, unknown> = { ...(existingMetadata || {}) };

  if (normalizedNote) {
    nextMetadata.order_note = normalizedNote;
  } else {
    delete nextMetadata.order_note;
  }

  try {
    await medusa.client.fetch(`/store/carts/${cart.id}`, {
      method: "POST",
      body: {
        metadata: nextMetadata,
      },
      headers: medusaHeaders(),
      cache: "no-store",
    });

    return {
      ok: true,
      message: normalizedNote ? "Note enregistrée." : "Note supprimée.",
    } as const;
  } catch (error) {
    const message =
      error instanceof Error && error.message
        ? error.message
        : "Impossible de mettre à jour la note de commande.";
    return { ok: false, message } as const;
  }
}

export async function updateLineItemQuantity(lineId: string, quantity: number) {
  const cart = await getCart();
  if (!cart) {
    return;
  }

  if (quantity <= 0) {
    await medusa.store.cart.deleteLineItem(cart.id, lineId, {}, medusaHeaders());
    await clearQuotePricingLock(cart.id);
    return;
  }

  await medusa.store.cart.updateLineItem(
    cart.id,
    lineId,
    { quantity },
    {},
    medusaHeaders(),
  );
  await clearQuotePricingLock(cart.id);
}

export async function removeLineItem(lineId: string) {
  const cart = await getCart();
  if (!cart) {
    return;
  }

  await medusa.store.cart.deleteLineItem(cart.id, lineId, {}, medusaHeaders());
  await clearQuotePricingLock(cart.id);
}

export async function applyPromoCode(code: string): Promise<{ ok: boolean; message: string }> {
  const normalized = code.trim();
  if (!normalized) {
    return { ok: false, message: "Veuillez saisir un code promo." };
  }

  const cart = await getCart();
  if (!cart) {
    return { ok: false, message: "Aucun panier actif." };
  }

  const headers = medusaHeaders();
  const attempts = [
    () =>
      medusa.client.fetch(`/store/carts/${cart.id}/promotions`, {
        method: "POST",
        body: { promo_codes: [normalized] },
        headers,
      }),
    () =>
      medusa.client.fetch(`/store/carts/${cart.id}/discounts`, {
        method: "POST",
        body: { promo_codes: [normalized] },
        headers,
      }),
  ];

  for (const attempt of attempts) {
    try {
      await attempt();
      return { ok: true, message: "Code promo appliqué." };
    } catch (error) {
      const errMessage =
        typeof error === "object" &&
        error &&
        "message" in error &&
        typeof (error as { message?: unknown }).message === "string"
          ? String((error as { message: string }).message)
          : "";
      if (errMessage) {
        return { ok: false, message: errMessage };
      }
      // Try next compatible endpoint.
    }
  }

  return { ok: false, message: "Code promo invalide ou non applicable." };
}

export async function removePromoCode(code: string): Promise<{ ok: boolean; message: string }> {
  const normalized = code.trim();
  if (!normalized) {
    return { ok: false, message: "Code promo invalide." };
  }

  const cart = await getCart();
  if (!cart) {
    return { ok: false, message: "Aucun panier actif." };
  }

  const headers = medusaHeaders();
  const attempts = [
    () =>
      medusa.client.fetch(`/store/carts/${cart.id}/promotions`, {
        method: "DELETE",
        body: { promo_codes: [normalized] },
        headers,
      }),
    () =>
      medusa.client.fetch(`/store/carts/${cart.id}/discounts`, {
        method: "DELETE",
        body: { promo_codes: [normalized] },
        headers,
      }),
  ];

  for (const attempt of attempts) {
    try {
      await attempt();
      return { ok: true, message: "Code promo retiré." };
    } catch {
      // Try next compatible endpoint.
    }
  }

  return { ok: false, message: "Impossible de retirer ce code promo." };
}

export async function transferCurrentCartToCustomer(customerToken: string) {
  const normalizedToken = customerToken.trim();
  if (!normalizedToken) {
    return;
  }

  const cart = await getCart();
  if (!cart) {
    return;
  }

  const headers = medusaHeaders();
  headers.Authorization = `Bearer ${normalizedToken}`;

  try {
    await medusa.store.cart.transferCart(cart.id, {}, headers);
  } catch {
    // Best effort: if transfer fails, checkout can still proceed as guest.
  }
}

function normalizePostalCode(raw: string) {
  return raw.replace(/\s+/g, "").toUpperCase();
}

function normalizePointAddress(point: MondialRelayPoint) {
  return {
    first_name: "Point",
    last_name: "Relais",
    address_1: point.address1,
    address_2: point.address2 || undefined,
    city: point.city,
    postal_code: normalizePostalCode(point.postalCode),
    country_code: point.countryCode.toLowerCase(),
    company: point.name,
  };
}

export async function updateCartMondialRelayPoint(point: MondialRelayPoint | null) {
  const cart = await getCart();
  if (!cart) {
    return { ok: false, message: "Aucun panier actif." } as const;
  }

  const metadata = (cart as { metadata?: Record<string, unknown> | null }).metadata;
  const nextMetadata = upsertMondialRelayPointMetadata(metadata, point);

  try {
    await medusa.client.fetch(`/store/carts/${cart.id}`, {
      method: "POST",
      body: {
        metadata: nextMetadata,
        shipping_address: point ? normalizePointAddress(point) : undefined,
      },
      headers: medusaHeaders(),
      cache: "no-store",
    });

    const refreshedCart = await fetchCartById(cart.id, medusaHeaders());
    const selectedOptionId =
      ((refreshedCart as { shipping_methods?: Array<{ shipping_option_id?: string }> } | null)?.shipping_methods || [])[0]
        ?.shipping_option_id || "";
    if (selectedOptionId) {
      await updateCartShippingOption(selectedOptionId);
    }

    return {
      ok: true,
      message: point ? "Point Relais enregistre." : "Point Relais supprime.",
    } as const;
  } catch (error) {
    const message =
      error instanceof Error && error.message
        ? error.message
        : "Impossible de mettre a jour le Point Relais.";
    return { ok: false, message } as const;
  }
}

export async function updateCartShippingOption(optionId: string) {
  const cart = await getCart();
  if (!cart) {
    return { ok: false, message: "Aucun panier actif." } as const;
  }

  const normalizedOptionId = optionId.trim();
  if (!normalizedOptionId) {
    return { ok: false, message: "Option de livraison invalide." } as const;
  }

  const shippingOptions = await listShippingOptionsForCart(cart.id, medusaHeaders());
  const selectedOption = shippingOptions.find((option) => option.id === normalizedOptionId);
  const shouldAttachMondialRelayData = isMondialRelayOption(selectedOption, normalizedOptionId);

  const body: Record<string, unknown> = { option_id: normalizedOptionId };
  if (shouldAttachMondialRelayData) {
    body.data = buildMondialRelayShippingData(cart, selectedOption);
  }

  const shippingMethods = (cart as { shipping_methods?: Array<{ id?: string }> }).shipping_methods || [];

  for (const shippingMethod of shippingMethods) {
    if (!shippingMethod.id) {
      continue;
    }

    try {
      await medusa.client.fetch(`/store/carts/${cart.id}/shipping-methods/${shippingMethod.id}`, {
        method: "DELETE",
        headers: medusaHeaders(),
        cache: "no-store",
      });
    } catch {
      // Best effort: continue replacing shipping methods.
    }
  }

  try {
    await medusa.client.fetch(`/store/carts/${cart.id}/shipping-methods`, {
      method: "POST",
      body,
      headers: medusaHeaders(),
      cache: "no-store",
    });

    await clearQuotePricingLock(cart.id);

    return { ok: true, message: "Mode de livraison mis a jour." } as const;
  } catch (error) {
    const message =
      error instanceof Error && error.message
        ? error.message
        : "Impossible de mettre a jour la livraison.";
    return { ok: false, message } as const;
  }
}


