import { FastifyReply, FastifyRequest } from 'fastify';
import { request as undiciRequest } from 'undici';

import { config } from '../config';
import { applyPriceDiscount } from '../pricing';
import { buildUpstreamHeaders, processResponseHeaders } from '../proxy/headers';
import { frontendIdFromSetCookie } from './customerAjxRewrite';
import { patchGrpcWebCartPrices } from './cartGrpcEncode';

const ARCH_ORIGIN = 'https://arch.sinsay.com';
const VARNISH_SESSION_PATH = '/pl/pl/varnish/ajax/newindex/';
const CHECKOUTCART_ADD_PATH = '/pl/pl/ajx/checkoutcart/add/';
/** Magento configurable attribute id used by Sinsay quick-shop (buildPayload$3). */
const MAGENTO_SIZE_ATTR_ID = 327;

async function ensureGuestCartSession(
  request: FastifyRequest,
  reply: FastifyReply,
): Promise<string | null> {
  const cookies = request.cookies as Record<string, string | undefined>;
  const existing = String(cookies.frontend ?? cookies.fastend ?? '').split(',')[0]?.trim();
  if (existing) return existing;

  const headers = buildUpstreamHeaders(
    request.headers as Record<string, string | string[] | undefined>,
    'www.sinsay.com',
    { preserveClientCookies: true },
  );
  headers.accept = 'application/json, text/plain, */*';

  const upstream = await undiciRequest(`${config.upstream.main}${VARNISH_SESSION_PATH}`, {
    method: 'GET',
    headers,
    throwOnError: false,
  });
  for await (const chunk of upstream.body) {
    void chunk;
  }

  const sessionId = frontendIdFromSetCookie(
    upstream.headers as Record<string, string | string[] | undefined>,
  );
  if (!sessionId) return null;

  const maxAge = 60 * 60 * 24 * 14;
  const cookieOpts = {
    path: '/',
    maxAge,
    httpOnly: true,
    sameSite: 'lax' as const,
  };
  reply.setCookie('frontend', sessionId, cookieOpts);
  reply.setCookie('fastend', sessionId, cookieOpts);

  return sessionId;
}

interface ArchSize {
  sizeName?: string;
  sku?: string;
  stock?: boolean;
  magentoId?: number;
  sizeId?: number;
  stockQuantity?: number;
}

interface ArchProduct {
  id?: number;
  sku?: string;
  sizes?: ArchSize[];
  isBlockedToCart?: boolean;
  price?: { final?: number; regular?: number };
}

interface MagentoCartAddLine {
  parentId: number;
  sizeId?: number;
  sku: string;
  qty: number;
}

async function fetchArchProduct(sku: string): Promise<ArchProduct | null> {
  const upstream = await undiciRequest(`${ARCH_ORIGIN}/api/17/product/${encodeURIComponent(sku)}`, {
    method: 'GET',
    headers: {
      accept: 'application/json',
      'user-agent': 'Mozilla/5.0',
    },
    throwOnError: false,
  });
  if (upstream.statusCode !== 200) return null;
  const chunks: Buffer[] = [];
  for await (const chunk of upstream.body) {
    chunks.push(chunk instanceof Buffer ? chunk : Buffer.from(chunk));
  }
  try {
    return JSON.parse(Buffer.concat(chunks).toString('utf8')) as ArchProduct;
  } catch {
    return null;
  }
}

function resolveMagentoCartAdd(
  product: ArchProduct,
  opts: { sizeName?: string; sizeSku?: string; qty: number },
): MagentoCartAddLine | { error: string } {
  if (product.isBlockedToCart) {
    return { error: 'Produkt niedostępny w koszyku.' };
  }

  const parentId = product.id;
  if (!parentId) {
    return { error: 'Nie udało się ustalić produktu.' };
  }

  const sizes = product.sizes ?? [];
  const sizeSku = String(opts.sizeSku ?? '').trim().toUpperCase();
  const sizeName = String(opts.sizeName ?? '').trim();

  const pick = (match: ArchSize | undefined): MagentoCartAddLine | { error: string } => {
    if (!match) return { error: 'Rozmiar jest niedostępny.' };
    if (match.stock === false || (match.stockQuantity != null && match.stockQuantity <= 0)) {
      return { error: `Rozmiar „${match.sizeName ?? sizeName}” jest niedostępny.` };
    }
    const sku = String(match.sku ?? product.sku ?? '').trim();
    if (!sku) return { error: 'Brak SKU wariantu.' };
    return {
      parentId,
      sizeId: match.sizeId,
      sku,
      qty: opts.qty,
    };
  };

  if (sizeSku) {
    const match = sizes.find((s) => String(s.sku ?? '').toUpperCase() === sizeSku);
    if (match) return pick(match);
  }

  if (sizeName) {
    const match = sizes.find(
      (s) => String(s.sizeName ?? '').toLowerCase() === sizeName.toLowerCase(),
    );
    if (match) return pick(match);
    return { error: `Rozmiar „${sizeName}” jest niedostępny.` };
  }

  const inStock = sizes.filter(
    (s) => s.stock !== false && (s.stockQuantity ?? 1) > 0 && s.sku,
  );
  if (inStock.length === 1) return pick(inStock[0]);
  if (sizes.length === 1) return pick(sizes[0]);

  if (sizes.length > 1) {
    return { error: 'Wybierz rozmiar przed dodaniem do koszyka.' };
  }

  const fallbackSku = String(product.sku ?? '').trim();
  if (!fallbackSku) return { error: 'Nie udało się ustalić wariantu produktu.' };
  return { parentId, sku: fallbackSku, qty: opts.qty };
}

function buildCheckoutcartAddBody(line: MagentoCartAddLine): string {
  const params = new URLSearchParams();
  params.set('products[0][product_id]', String(line.parentId));
  params.set('products[0][qty]', String(line.qty));
  params.set('products[0][version]', '1');
  params.set('products[0][sku]', line.sku);
  if (line.sizeId != null) {
    params.set(`products[0][super_attribute][${MAGENTO_SIZE_ATTR_ID}]`, String(line.sizeId));
  }
  return params.toString();
}

function skuCandidates(sku: string): string[] {
  const out: string[] = [];
  const normalized = String(sku ?? '').trim().toUpperCase();
  if (!normalized) return out;
  out.push(normalized);
  const parts = normalized.split('-');
  if (parts.length >= 3) {
    const style = parts.slice(0, -1).join('-');
    if (style && !out.includes(style)) out.push(style);
  }
  return out;
}

/** POST /api/mirror/cart/add — official Sinsay Magento cart (checkoutcart/add). */
export async function handleMirrorCartAdd(
  request: FastifyRequest,
  reply: FastifyReply,
): Promise<void> {
  const body = (request.body ?? {}) as {
    sku?: string;
    sizeName?: string;
    sizeSku?: string;
    qty?: number;
  };

  const sku = String(body.sku ?? '').trim().toUpperCase();
  if (!sku) {
    reply.status(400).send({ ok: false, error: 'sku is required' });
    return;
  }

  const qty = Math.max(1, Math.min(99, Math.floor(Number(body.qty) || 1)));

  let product: ArchProduct | null = null;
  for (const candidate of skuCandidates(sku)) {
    product = await fetchArchProduct(candidate);
    if (product?.id || (product?.sizes && product.sizes.length)) break;
  }

  if (!product) {
    reply.status(404).send({ ok: false, error: 'Nie znaleziono produktu.' });
    return;
  }

  const resolved = resolveMagentoCartAdd(product, {
    sizeName: body.sizeName,
    sizeSku: body.sizeSku,
    qty,
  });
  if ('error' in resolved) {
    reply.status(400).send({ ok: false, error: resolved.error });
    return;
  }

  const sessionId = await ensureGuestCartSession(request, reply);
  if (!sessionId) {
    reply.status(400).send({
      ok: false,
      error: 'Brak sesji koszyka Sinsay. Odśwież stronę i spróbuj ponownie.',
    });
    return;
  }

  const upstreamHeaders = buildUpstreamHeaders(
    request.headers as Record<string, string | string[] | undefined>,
    'www.sinsay.com',
    { preserveClientCookies: true },
  );
  const cookieParts = (upstreamHeaders.cookie ?? '').split(/;\s*/).filter(Boolean);
  const withoutFrontend = cookieParts.filter(
    (c) => !/^frontend=/i.test(c) && !/^fastend=/i.test(c),
  );
  withoutFrontend.push(`frontend=${sessionId}`, `fastend=${sessionId}`);
  upstreamHeaders.cookie = withoutFrontend.join('; ');
  upstreamHeaders['content-type'] = 'application/x-www-form-urlencoded';
  upstreamHeaders.accept = 'application/json, text/plain, */*';
  upstreamHeaders['x-requested-with'] = 'XMLHttpRequest';

  const upstream = await undiciRequest(`${config.upstream.main}${CHECKOUTCART_ADD_PATH}`, {
    method: 'POST',
    headers: upstreamHeaders,
    body: buildCheckoutcartAddBody(resolved),
    throwOnError: false,
  });

  const respChunks: Buffer[] = [];
  for await (const chunk of upstream.body) {
    respChunks.push(chunk instanceof Buffer ? chunk : Buffer.from(chunk));
  }
  const respBody = Buffer.concat(respChunks);

  type CheckoutcartAddResponse = { status?: boolean; message?: string; products?: unknown[] };
  let data: CheckoutcartAddResponse | null = null;
  try {
    data = JSON.parse(respBody.toString('utf8')) as CheckoutcartAddResponse;
  } catch {
    data = null;
  }

  if (upstream.statusCode !== 200 || !data?.status) {
    reply.status(502).send({
      ok: false,
      error:
        data?.message ||
        'Nie udało się dodać do koszyka (błąd Sinsay).',
      upstreamStatus: upstream.statusCode,
    });
    return;
  }

  const mirror = {
    mirrorOrigin: config.origin,
    mirrorDomain: config.domain,
    requestOrigin: String(request.headers.origin ?? '') || undefined,
  };
  const responseHeaders = processResponseHeaders(
    upstream.headers as Record<string, string | string[] | undefined>,
    mirror,
  );
  for (const [k, v] of Object.entries(responseHeaders)) {
    reply.header(k, v as string);
  }

  const upstreamPrice = Number(product.price?.final ?? product.price?.regular ?? 0);
  const discounted = upstreamPrice > 0 ? applyPriceDiscount(upstreamPrice) : undefined;

  reply.send({
    ok: true,
    productId: resolved.parentId,
    sku: resolved.sku,
    qty: resolved.qty,
    price: discounted,
    currency: 'PLN',
    message: data?.message,
  });
}

/** Apply discount to gRPC-web cart responses (Get, etc.). */
export function maybePatchCartGrpcBody(path: string, body: Buffer): Buffer {
  const pct = config.pricing.discountPercent;
  if (pct <= 0 || pct >= 100) return body;
  if (!/\/CartService\//i.test(path)) return body;
  return patchGrpcWebCartPrices(body, pct);
}
