import sql from 'mssql';
import { getPool } from '../db.js';
import { getCustomerGroupIds } from './customer-groups.js';
import { getProductAttributes } from './product-attributes.js';
import { getActiveShopId } from '../shop.js';

const LANGUAGE_ID = Number(process.env.LANGUAGE_ID) || 1;
const TAX_ZONE_NAME = process.env.TAX_ZONE_NAME || 'Zone-EU';

const PRODUCT_LIST_SQL = `
WITH TaxRates AS (
  SELECT kSteuerklasse, fSteuersatz
  FROM dbo.tSteuersatz
  WHERE kSteuerzone IN (SELECT kSteuerzone FROM dbo.tSteuerzone WHERE cName = @taxZoneName)
),
ImageRV AS (
  SELECT kArtikel, MAX(CONVERT(BIGINT, bRowversion)) AS maxImageRV
  FROM dbo.tArtikelbildPlattform
  WHERE kShop = @kShop
  GROUP BY kArtikel
)
SELECT TOP (@limit)
  a.kArtikel AS id,
  a.cArtNr AS sku,
  ab.cName AS name,
  a.fVKNetto AS netPrice,
  tr.fSteuersatz AS taxRate,
  a.dErstelldatum AS createdAt,
  CASE
    WHEN ir.maxImageRV IS NOT NULL AND ir.maxImageRV > CONVERT(BIGINT, a.bRowversion)
    THEN ir.maxImageRV
    ELSE CONVERT(BIGINT, a.bRowversion)
  END AS lastChanged,
  (
    SELECT TOP 1 img.cHash
    FROM dbo.tArtikelbildPlattform abp
    INNER JOIN dbo.tBild img ON img.kBild = abp.kBild
    WHERE abp.kArtikel = a.kArtikel
    ORDER BY abp.nNr
  ) AS imgHash,
  (
    SELECT STRING_AGG(CAST(ka.kKategorie AS varchar(20)), ',')
    FROM dbo.tkategorieartikel ka
    WHERE ka.kArtikel = a.kArtikel
  ) AS categoryIds,
  a.nIstVater AS isParent,
  a.kVaterArtikel AS parentArticleId,
  CASE WHEN a.kStueckliste <> 0 THEN '1' ELSE '0' END AS isCompositeProduct,
  (
    SELECT TOP 1 pv.cVariantName
    FROM Pos.vProductVariant pv
    WHERE pv.kProduct = a.kArtikel
  ) AS variantName
FROM dbo.tArtikel a
INNER JOIN dbo.tArtikelBeschreibung ab ON ab.kArtikel = a.kArtikel AND ab.kSprache = @languageId
LEFT JOIN TaxRates tr ON tr.kSteuerklasse = a.kSteuerklasse
LEFT JOIN ImageRV ir ON ir.kArtikel = a.kArtikel
WHERE a.cAktiv = 'Y'
  AND (@kShop = 0 OR EXISTS (
    SELECT 1 FROM dbo.tKategorieArtikel ka
    INNER JOIN dbo.tKategorieShop ks ON ks.kKategorie = ka.kKategorie AND ks.kShop = @kShop
    WHERE ka.kArtikel = a.kArtikel
  ))
  AND (
    CONVERT(BIGINT, a.bRowversion) > @cursor
    OR (ir.maxImageRV IS NOT NULL AND ir.maxImageRV > @cursor)
  )
ORDER BY lastChanged ASC;
`;

function priceOverridesSql(articleIds) {
  const idList = articleIds.join(',');
  return `
    SELECT p.kArtikel AS articleId, p.kKundenGruppe AS customerGroupId, MIN(pd.fNettoPreis) AS netPrice
    FROM dbo.tPreis p
    INNER JOIN dbo.tPreisDetail pd ON pd.kPreis = p.kPreis
    WHERE p.kArtikel IN (${idList}) AND p.kShop = 0 AND pd.nAnzahlAb = 0
    GROUP BY p.kArtikel, p.kKundenGruppe;
  `;
}

function formatDateTime(date) {
  if (!date) {
    return '0001-01-01 00:00:00';
  }
  const pad = (n) => String(n).padStart(2, '0');
  return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
}

function grossPrice(netPrice, taxRate) {
  return (Number(netPrice) * (1 + Number(taxRate || 0) / 100)).toFixed(2);
}

export async function getProductList({ cursor = 0, limit = 20 } = {}) {
  const pool = getPool();

  const [productResult, customerGroupIds] = await Promise.all([
    pool
      .request()
      .input('cursor', sql.BigInt, cursor)
      .input('limit', sql.Int, limit)
      .input('languageId', sql.Int, LANGUAGE_ID)
      .input('taxZoneName', sql.NVarChar, TAX_ZONE_NAME)
      .input('kShop', sql.Int, getActiveShopId())
      .query(PRODUCT_LIST_SQL),
    getCustomerGroupIds(),
  ]);

  const products = productResult.recordset;
  const articleIds = products.map((p) => p.id);

  const overridesByArticle = new Map();
  let attributesByArticle = new Map();
  if (articleIds.length > 0) {
    const [overrideResult, attributeMap] = await Promise.all([
      pool.request().query(priceOverridesSql(articleIds)),
      getProductAttributes(pool, articleIds),
    ]);
    attributesByArticle = attributeMap;
    for (const row of overrideResult.recordset) {
      if (!overridesByArticle.has(row.articleId)) {
        overridesByArticle.set(row.articleId, new Map());
      }
      overridesByArticle.get(row.articleId).set(row.customerGroupId, row.netPrice);
    }
  }

  return products.map((product) => {
    const overrides = overridesByArticle.get(product.id);
    const basePrice = grossPrice(product.netPrice, product.taxRate);

    const prices = customerGroupIds.map((customerGroupId) => {
      const overrideNetPrice = overrides?.get(customerGroupId);
      const price =
        overrideNetPrice !== undefined ? grossPrice(overrideNetPrice, product.taxRate) : basePrice;
      return {
        customerGroupId: String(customerGroupId),
        customerId: '0',
        price,
        quantity: '0',
      };
    });

    const categoryIds = product.categoryIds ? product.categoryIds.split(',') : [];
    const articleAttributes = attributesByArticle.get(product.id);

    return {
      _id: String(product.id),
      imghash: product.imgHash ?? null,
      imgsrc: product.imgHash ?? null,
      sku: product.sku,
      name: product.name,
      tax_rate: String(Math.round(Number(product.taxRate || 0))),
      price: basePrice,
      created_at: formatDateTime(product.createdAt),
      lastChanged: String(product.lastChanged),
      categories_id: categoryIds[0] ?? '0',
      categories: categoryIds.map((categoryId) => ({ categoryId })),
      prices,
      is_parent: product.isParent ? '1' : '0',
      parent: product.parentArticleId > 0 ? String(product.parentArticleId) : '0',
      variants: product.variantName ?? '',
      isCompositeProduct: product.isCompositeProduct,
      attributes: articleAttributes?.attributes ?? [],
      ...(articleAttributes?.deposit ?? {}),
    };
  });
}
