"use server";

import { cookies } from "next/headers";
import { HttpTypes } from "@medusajs/types";
import { medusa, medusaHeaders } from "@/lib/medusa/client";
import type { CustomerQuote } from "@/lib/medusa/quotes";

const CUSTOMER_TOKEN_COOKIE = "stylunique_customer_token";

export type AccountSnapshot = {
  authenticated: boolean;
  customer: HttpTypes.StoreCustomer | null;
  addresses: HttpTypes.StoreCustomerAddress[];
  orders: HttpTypes.StoreOrder[];
  ordersCount: number;
  quotes: CustomerQuote[];
};

type AccountSnapshotOptions = {
  ordersLimit?: number;
  ordersOffset?: number;
};

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

export async function getCustomerTokenFromCookie() {
  return getCustomerToken();
}

export async function getCustomerAuthState() {
  const token = await getCustomerToken();

  if (!token) {
    return { authenticated: false, customer: null };
  }

  try {
    const { customer } = await medusa.store.customer.retrieve({}, authHeaders(token));
    return { authenticated: Boolean(customer), customer: customer || null };
  } catch {
    return { authenticated: false, customer: null };
  }
}

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

export async function clearCustomerToken() {
  const cookieStore = await cookies();
  cookieStore.delete(CUSTOMER_TOKEN_COOKIE);
}

function authHeaders(token?: string) {
  const headers = medusaHeaders();

  if (token) {
    headers.Authorization = `Bearer ${token}`;
  }

  return headers;
}

const ORDER_FIELDS_WITH_TRACKING =
  "*items,*shipping_methods,*fulfillments,*fulfillments.data,*fulfillments.metadata,+display_id,+payment_status,+fulfillment_status,+created_at,+total,+subtotal,+shipping_total,+tax_total,+discount_total,+metadata";

type CustomerOrdersResponse = {
  orders?: HttpTypes.StoreOrder[];
  count?: number;
  offset?: number;
  limit?: number;
};

function sortOrdersByNewest(orders: HttpTypes.StoreOrder[]) {
  return [...orders].sort((a, b) => {
    const left = new Date(a.created_at || 0).getTime();
    const right = new Date(b.created_at || 0).getTime();
    return right - left;
  });
}

async function listCustomerOrdersWithTracking(token: string, options?: AccountSnapshotOptions) {
  const limit = Math.max(1, Math.min(options?.ordersLimit ?? 50, 100));
  const offset = Math.max(0, options?.ordersOffset ?? 0);

  try {
    const response = await medusa.client.fetch<CustomerOrdersResponse>("/store/orders", {
      method: "GET",
      query: {
        limit,
        offset,
        fields: ORDER_FIELDS_WITH_TRACKING,
      },
      headers: authHeaders(token),
      cache: "no-store",
    });

    const orders = sortOrdersByNewest(response.orders || []);
    return {
      orders,
      count: typeof response.count === "number" ? response.count : orders.length,
    };
  } catch {
    const fallback = (await medusa.store.order.list({ limit, offset }, authHeaders(token))) as CustomerOrdersResponse;
    const orders = sortOrdersByNewest(fallback.orders || []);
    return {
      orders,
      count: typeof fallback.count === "number" ? fallback.count : orders.length,
    };
  }
}

function readTokenFromResponse(payload: unknown) {
  if (!payload || typeof payload !== "object") {
    return null;
  }

  const maybeToken = (payload as { token?: unknown }).token;
  return typeof maybeToken === "string" && maybeToken ? maybeToken : null;
}

export async function loginCustomer(email: string, password: string) {
  const response = await medusa.client.fetch<unknown>("/auth/customer/emailpass", {
    method: "POST",
    body: { email, password },
    headers: medusaHeaders(),
    cache: "no-store",
  });

  const token = readTokenFromResponse(response);

  if (!token) {
    throw new Error("Authentication failed.");
  }

  await setCustomerToken(token);
}

export async function registerCustomer(input: {
  email: string;
  password: string;
  firstName?: string;
  lastName?: string;
  phone?: string;
}) {
  const registration = await medusa.client.fetch<unknown>("/auth/customer/emailpass/register", {
    method: "POST",
    body: { email: input.email, password: input.password },
    headers: medusaHeaders(),
    cache: "no-store",
  });

  const registrationToken = readTokenFromResponse(registration);

  if (!registrationToken) {
    throw new Error("Registration failed.");
  }

  await medusa.store.customer.create(
    {
      email: input.email,
      first_name: input.firstName || undefined,
      last_name: input.lastName || undefined,
      phone: input.phone || undefined,
    },
    {},
    authHeaders(registrationToken),
  );

  await loginCustomer(input.email, input.password);
}

export async function getAccountSnapshot(options?: AccountSnapshotOptions): Promise<AccountSnapshot> {
  const token = await getCustomerToken();

  if (!token) {
    return { authenticated: false, customer: null, addresses: [], orders: [], ordersCount: 0, quotes: [] };
  }

  try {
    const [{ customer }, addressResponse, orderResponse] = await Promise.all([
      medusa.store.customer.retrieve({}, authHeaders(token)),
      medusa.store.customer.listAddress({ limit: 20 }, authHeaders(token)),
      listCustomerOrdersWithTracking(token, options),
    ]);
    const { listCustomerQuotes } = await import("@/lib/medusa/quotes");
    const quotes = await listCustomerQuotes({ authenticated: true, customer });

    return {
      authenticated: true,
      customer,
      addresses: addressResponse.addresses || [],
      orders: orderResponse.orders,
      ordersCount: orderResponse.count,
      quotes,
    };
  } catch {
    // Cookie mutation is only allowed in Server Actions/Route Handlers, not during RSC render.
    // Keep this path read-only and let explicit actions handle token cleanup.
    return { authenticated: false, customer: null, addresses: [], orders: [], ordersCount: 0, quotes: [] };
  }
}

export async function getCustomerOrderById(orderId: string): Promise<HttpTypes.StoreOrder | null> {
  const token = await getCustomerToken();
  if (!token) {
    return null;
  }

  try {
    const { order } = await medusa.store.order.retrieve(orderId, {}, authHeaders(token));
    return order || null;
  } catch {
    return null;
  }
}

async function requireToken() {
  const token = await getCustomerToken();

  if (!token) {
    throw new Error("Not authenticated.");
  }

  return token;
}

export async function updateCustomerProfile(input: {
  firstName?: string;
  lastName?: string;
  phone?: string;
}) {
  const token = await requireToken();

  await medusa.store.customer.update(
    {
      first_name: input.firstName || undefined,
      last_name: input.lastName || undefined,
      phone: input.phone || undefined,
    },
    {},
    authHeaders(token),
  );
}

export async function createCustomerAddress(input: {
  firstName?: string;
  lastName?: string;
  company?: string;
  address1: string;
  address2?: string;
  city: string;
  province?: string;
  postalCode: string;
  countryCode: string;
  phone?: string;
  isDefaultShipping?: boolean;
  isDefaultBilling?: boolean;
}) {
  const token = await requireToken();

  await medusa.store.customer.createAddress(
    {
      first_name: input.firstName || undefined,
      last_name: input.lastName || undefined,
      company: input.company || undefined,
      address_1: input.address1,
      address_2: input.address2 || undefined,
      city: input.city,
      province: input.province || undefined,
      postal_code: input.postalCode,
      country_code: input.countryCode.toLowerCase(),
      phone: input.phone || undefined,
      is_default_shipping: Boolean(input.isDefaultShipping),
      is_default_billing: Boolean(input.isDefaultBilling),
    },
    {},
    authHeaders(token),
  );
}

export async function deleteCustomerAddress(addressId: string) {
  const token = await requireToken();
  await medusa.store.customer.deleteAddress(addressId, authHeaders(token));
}

export async function deleteCustomerAccount() {
  const token = await requireToken();

  await medusa.client.fetch("/store/custom/account", {
    method: "DELETE",
    headers: authHeaders(token),
    cache: "no-store",
  });
}
