import { ROUTES } from '@theme/routes';
import type {
  Basket,
  BreadcrumbResultType,
  GetCategoryResponse,
  Product,
  ProductResult
} from '@akinon/next/types';

type UnknownRecord = Record<string, unknown>;

const toRecord = (value: unknown): UnknownRecord =>
  value && typeof value === 'object' ? (value as UnknownRecord) : {};

const toStringValue = (value: unknown, fallback = ''): string =>
  typeof value === 'string' ? value : fallback;

const humanizeSlug = (value: string) =>
  value
    .split('-')
    .filter(Boolean)
    .map(part => part.charAt(0).toUpperCase() + part.slice(1))
    .join(' ');

const normalizeProductImages = (
  product?: Product | null
): Array<Record<string, unknown>> =>
  (product?.productimage_set || []).map((item, index) => ({
    ...item,
    url: item.image,
    alt: `${product?.name || 'Product'} ${index + 1}`
  }));

const normalizeAttributeEntries = (
  attributes: unknown
): Array<Record<string, string>> => {
  const record = toRecord(attributes);

  return Object.values(record)
    .map(entry => {
      const typedEntry = toRecord(entry);
      const label = toStringValue(typedEntry.label);
      const value = toStringValue(typedEntry.value);

      if (!label && !value) {
        return null;
      }

      return { label, value };
    })
    .filter((entry): entry is { label: string; value: string } => entry !== null);
};

export const normalizeProductEntry = (
  product?: Product | null
): Record<string, unknown> | null => {
  if (!product) {
    return null;
  }

  const activePrice = toRecord((product as Product & UnknownRecord).active_price);
  const images = normalizeProductImages(product);

  return {
    ...product,
    title: product.name,
    name: product.name,
    url: product.absolute_url,
    image: product.image || images[0]?.url || '',
    images,
    price: activePrice.price ?? product.price,
    retailPrice: activePrice.retail_price ?? product.retail_price,
    currency: activePrice.currency_type ?? product.currency_type ?? '',
    description: product.description || '',
    attributes: normalizeAttributeEntries(product.attributes_kwargs)
  };
};

export const buildProductPageContext = (data: ProductResult) => {
  const normalizedProduct = normalizeProductEntry(data.product);
  const normalizedSelectedVariant = normalizeProductEntry(data.selected_variant);

  return {
    page: {
      type: 'product',
      title: normalizedProduct?.title || 'Product',
      path: normalizedProduct?.url || ''
    },
    product: {
      ...normalizedProduct,
      selectedVariant: normalizedSelectedVariant,
      selected_variant: normalizedSelectedVariant,
      variants: data.variants || []
    }
  };
};

export const buildHomepagePageContext = () => ({
  page: {
    type: 'homepage',
    title: 'Homepage',
    slug: 'homepage',
    path: ROUTES.HOME
  },
  homepage: {
    title: 'Homepage',
    slug: 'homepage',
    path: ROUTES.HOME
  }
});

export const buildCustomPageContext = (slug: string) => {
  const title = humanizeSlug(slug) || 'Custom Page';
  const path = `/pages/${slug}`;

  return {
    page: {
      type: 'custom-page',
      title,
      slug,
      path
    },
    customPage: {
      title,
      slug,
      path
    }
  };
};

export const buildListingPageContext = ({
  data,
  breadcrumbData,
  pageType,
  path
}: {
  data: GetCategoryResponse;
  breadcrumbData?: BreadcrumbResultType[];
  pageType: 'category' | 'search' | 'plp';
  path?: string;
}) => {
  const normalizedProducts = (data.products || [])
    .map(product => normalizeProductEntry(product))
    .filter((product): product is Record<string, unknown> => product !== null);
  const categorySeoTitle = toStringValue(
    data.category?.attributes?.category_seo_title?.value?.text
  );
  const effectivePath = path || data.category?.absolute_url || ROUTES.HOME;
  const totalProducts =
    Number(toRecord(data.pagination).count) || normalizedProducts.length;
  const title =
    pageType === 'search'
      ? data.search_text
        ? `Search results for ${data.search_text}`
        : 'Search Results'
      : data.category?.name || 'Product Listing';

  const category = {
    ...(data.category || {}),
    title: data.category?.name || '',
    name: data.category?.name || '',
    url: data.category?.absolute_url || '',
    description: categorySeoTitle,
    seoTitle: categorySeoTitle,
    facets: data.facets || [],
    products: normalizedProducts
  };

  const listingBase = {
    title,
    path: effectivePath,
    query: data.search_text || '',
    products: normalizedProducts,
    totalProducts,
    resultCount: totalProducts,
    facets: data.facets || [],
    sorters: data.sorters || [],
    pagination: data.pagination || {},
    category
  };

  return {
    page: {
      type: pageType,
      title,
      path: effectivePath
    },
    category,
    listing: {
      ...listingBase,
      breadcrumbs: breadcrumbData || []
    },
    search: {
      ...listingBase,
      title: data.search_text
        ? `Search results for ${data.search_text}`
        : 'Search Results'
    },
    plp: {
      ...listingBase,
      title: data.category?.name || 'Product Listing'
    },
    breadcrumbs: breadcrumbData || []
  };
};

export const buildBasketPageContext = ({
  basket,
  path
}: {
  basket?: Basket | null;
  path?: string;
}) => {
  const normalizedItems = (basket?.basketitem_set || []).map(item => {
    const normalizedProduct = normalizeProductEntry(item.product);

    return {
      ...item,
      title: normalizedProduct?.title || item.product?.name || '',
      name: normalizedProduct?.name || item.product?.name || '',
      url: normalizedProduct?.url || item.product?.absolute_url || '',
      image:
        item.image ||
        (typeof normalizedProduct?.image === 'string'
          ? normalizedProduct.image
          : ''),
      price: item.price || normalizedProduct?.price || '',
      retailPrice: item.retail_price || normalizedProduct?.retailPrice || '',
      totalAmount: item.total_amount || '',
      unitPrice: item.unit_price || '',
      currency: item.currency_type || normalizedProduct?.currency || '',
      quantity: item.quantity,
      attributes: normalizeAttributeEntries(
        item.attributes_kwargs || item.product?.attributes_kwargs
      ),
      product: normalizedProduct
    };
  });

  return {
    page: {
      type: 'basket',
      title: 'Basket',
      path: path || ROUTES.BASKET
    },
    basket: {
      id: basket?.pk || null,
      path: path || ROUTES.BASKET,
      checkoutUrl: ROUTES.CHECKOUT,
      continueShoppingUrl: ROUTES.HOME,
      isEmpty: normalizedItems.length === 0,
      itemCount: normalizedItems.length,
      totalQuantity: basket?.total_quantity || 0,
      totalAmount: basket?.total_amount || '',
      totalProductAmount: basket?.total_product_amount || '',
      totalDiscountAmount: basket?.total_discount_amount || '',
      voucherCode: basket?.voucher_code || '',
      discounts: basket?.discounts || [],
      items: normalizedItems
    }
  };
};

export const buildAccountPageContext = ({
  path,
  profileInfo,
  sessionUser
}: {
  path?: string;
  profileInfo?: UnknownRecord | null;
  sessionUser?: UnknownRecord | null;
}) => {
  const normalizedPath = path || ROUTES.ACCOUNT;
  const firstName =
    toStringValue(profileInfo?.first_name) ||
    toStringValue(sessionUser?.firstName) ||
    toStringValue(sessionUser?.name).split(' ')[0] ||
    '';
  const lastName =
    toStringValue(profileInfo?.last_name) ||
    toStringValue(sessionUser?.lastName) ||
    toStringValue(sessionUser?.name).split(' ').slice(1).join(' ') ||
    '';
  const email =
    toStringValue(profileInfo?.email) || toStringValue(sessionUser?.email);
  const fullName =
    [firstName, lastName].filter(Boolean).join(' ') ||
    toStringValue(sessionUser?.name);

  return {
    page: {
      type: 'account',
      title: 'Account',
      path: normalizedPath
    },
    account: {
      path: normalizedPath,
      route: normalizedPath,
      user: {
        firstName,
        lastName,
        fullName,
        email,
        phone: toStringValue(profileInfo?.phone),
        gender: toStringValue(profileInfo?.gender)
      }
    }
  };
};
