import { StyleGenerator } from '@pdfdraft/core/lib/html';
import type { ProductTableTemplateSettings } from './constants/types';
import { DEFAULT_PRODUCT_TABLE_TEMPLATE_SETTINGS } from './constants/types';
import { PRODUCT_TABLE_NAMESPACE } from './constants/types';
import { getTemplateSpec } from './constants/templates';
import type { ProductTableTemplateSpec } from './constants/templates';

const styleGenerator = new StyleGenerator();

function toPx(value: unknown): number | undefined {
	if (typeof value === 'number' && Number.isFinite(value)) return value;
	if (typeof value === 'string') {
		const n = Number.parseFloat(value);
		return Number.isFinite(n) ? n : undefined;
	}
	return undefined;
}

function colWeightsParts(
	showThumbnail: boolean,
	showProductName: boolean,
	showQuantity: boolean,
	showUnitPrice: boolean,
	showLineTotal: boolean,
	showSku: boolean,
): number[] {
	return [
		showThumbnail ? 1.25 : 0,
		showProductName ? 2.0 : 0,
		showQuantity ? 1.0 : 0,
		showUnitPrice ? 1.0 : 0,
		showLineTotal ? 1.0 : 0,
		showSku ? 1.0 : 0,
	];
}

function buildModernZebraTableHtml(opts: {
	data: any;
	props: ProductTableTemplateSettings;
	spec: ProductTableTemplateSpec;
	showThumbnail: boolean;
	showProductName: boolean;
	showQuantity: boolean;
	showUnitPrice: boolean;
	showLineTotal: boolean;
	showSku: boolean;
	textStyle: NonNullable<ProductTableTemplateSettings['textStyle']>;
	maxRows: number;
	styleAttr: string;
	elementWidthPx: number | undefined;
}): string {
	const {
		data,
		props,
		spec,
		showThumbnail,
		showProductName,
		showQuantity,
		showUnitPrice,
		showLineTotal,
		showSku,
		textStyle,
		maxRows,
		styleAttr,
		elementWidthPx,
	} = opts;

	const headerBg =
		(props.headerBackgroundColor && props.headerBackgroundColor.trim() !== ''
			? props.headerBackgroundColor
			: spec.headerBg) ?? '#000000';
	const headerText =
		(props.headerTextColor && props.headerTextColor.trim() !== ''
			? props.headerTextColor
			: (spec.headerTextColor ?? '#ffffff'));
	const zebraBg = spec.zebraEvenBg ?? '#f5f5f5';
	const bodyColor = textStyle.color ?? spec.bodyMutedColor ?? '#6b7280';
	const r = spec.rowBorderRadiusPx ?? 8;
	const gap = spec.rowGapPx ?? 8;
	const pad = spec.cellPaddingPx;
	const fontFamily = textStyle.fontFamily;
	const fontWeight = textStyle.fontWeight;

	const weights = colWeightsParts(
		showThumbnail,
		showProductName,
		showQuantity,
		showUnitPrice,
		showLineTotal,
		showSku,
	);
	const sumW = weights.reduce((a, b) => a + b, 0) || 1;
	const colPct = weights.map((w) => (w / sumW) * 100);

	let ci = 0;
	const colgroupParts: string[] = [];
	if (showThumbnail) {
		colgroupParts.push(`<col style="width:${colPct[ci]}%"/>`);
		ci++;
	}
	if (showProductName) {
		colgroupParts.push(`<col style="width:${colPct[ci]}%"/>`);
		ci++;
	}
	if (showQuantity) {
		colgroupParts.push(`<col style="width:${colPct[ci]}%"/>`);
		ci++;
	}
	if (showUnitPrice) {
		colgroupParts.push(`<col style="width:${colPct[ci]}%"/>`);
		ci++;
	}
	if (showLineTotal) {
		colgroupParts.push(`<col style="width:${colPct[ci]}%"/>`);
		ci++;
	}
	if (showSku) {
		colgroupParts.push(`<col style="width:${colPct[ci]}%"/>`);
	}

	const tableFont = [
		elementWidthPx ? `width:${elementWidthPx}px` : 'width:100%',
		'border-collapse:separate',
		`border-spacing:0 ${gap}px`,
		`margin-top:-${gap}px`,
		'table-layout:fixed',
		`font-size:${spec.fontSizePx}px`,
		`line-height:${spec.lineHeight}`,
		fontFamily ? `font-family:${fontFamily}` : '',
		fontWeight != null ? `font-weight:${fontWeight}` : '',
	].filter(Boolean).join(';');

	const esc = data.id.replace(/"/g, '\\"');
	const scope = `[data-pdfdraft-pt-instance="${esc}"]`;

	const zebraStyle = `
<style type="text/css">
${scope} .pdfdraft-pt-mz-inner table { ${tableFont} }
${scope} .pdfdraft-pt-mz-inner th,
${scope} .pdfdraft-pt-mz-inner td {
	border: none;
	box-sizing: border-box;
	word-wrap: break-word;
	overflow: hidden;
	vertical-align: middle;
}
${scope} .pdfdraft-pt-mz-inner thead th {
	background: ${headerBg};
	color: ${headerText};
	font-weight: ${spec.headerFontWeight};
	padding: ${pad}px;
}
${scope} .pdfdraft-pt-mz-inner thead th:first-child {
	border-top-left-radius: ${r}px;
	border-top-right-radius: 0;
	border-bottom-left-radius: 0;
	border-bottom-right-radius: 0;
}
${scope} .pdfdraft-pt-mz-inner thead th:last-child {
	border-top-right-radius: ${r}px;
}
${scope} .pdfdraft-pt-mz-inner tbody tr:nth-child(odd) td {
	background: #ffffff;
	color: ${bodyColor};
	padding: ${pad}px;
}
${scope} .pdfdraft-pt-mz-inner tbody tr:nth-child(even) td {
	background: ${zebraBg};
	color: ${bodyColor};
	padding: ${pad}px;
}
${scope} .pdfdraft-pt-mz-inner tbody tr:nth-child(even) td:first-child {
	border-top-left-radius: ${r}px;
	border-bottom-left-radius: ${r}px;
}
${scope} .pdfdraft-pt-mz-inner tbody tr:nth-child(even) td:last-child {
	border-top-right-radius: ${r}px;
	border-bottom-right-radius: ${r}px;
}
</style>`.trim();

	const align = {
		thumb: 'center',
		product: 'left',
		qty: 'center',
		unit: 'right',
		total: 'right',
		sku: 'left',
	} as const;

	const hThumb = showThumbnail
		? `<th style="text-align:${align.thumb};height:${spec.headerHeightPx}px">Thumbnail</th>`
		: '';
	const hProduct = showProductName
		? `<th style="text-align:${align.product};height:${spec.headerHeightPx}px;padding-left:${pad + 4}px">Product Name</th>`
		: '';
	const hQty = showQuantity
		? `<th style="text-align:${align.qty};height:${spec.headerHeightPx}px">Quantity</th>`
		: '';
	const hUnit = showUnitPrice
		? `<th style="text-align:${align.unit};height:${spec.headerHeightPx}px">Price (Unit Price)</th>`
		: '';
	const hTotal = showLineTotal
		? `<th style="text-align:${align.total};height:${spec.headerHeightPx}px;padding-right:${pad + 4}px">Total (line total)</th>`
		: '';
	const hSku = showSku
		? `<th style="text-align:${align.sku};height:${spec.headerHeightPx}px">SKU</th>`
		: '';

	const productNameCell = `<td style="text-align:${align.product};height:${spec.rowHeightPx}px;padding-left:${pad + 4}px"><div style="width:100%;">{{item.product_display_name}}</div></td>`;
	const quantityCell = `<td style="text-align:${align.qty};height:${spec.rowHeightPx}px"><div style="width:100%;">{{item.quantity}}</div></td>`;
	const unitPriceCell = `<td style="text-align:${align.unit};height:${spec.rowHeightPx}px"><div style="width:100%;">{{item.unit_price}}</div></td>`;
	const lineTotalCell = `<td style="text-align:${align.total};height:${spec.rowHeightPx}px;padding-right:${pad + 4}px"><div style="width:100%;">{{item.line_total}}</div></td>`;
	const skuCell = `<td style="text-align:${align.sku};height:${spec.rowHeightPx}px"><div style="width:100%;">{{item.sku}}</div></td>`;
	const thumbCell = `<td style="text-align:${align.thumb};height:${spec.rowHeightPx}px"><div style="width:${spec.thumbnailSizePx}px;height:${spec.thumbnailSizePx}px;overflow:hidden;margin:0 auto;">{{item.product_image}}</div></td>`;

	const rowCells: string[] = [];
	if (showThumbnail) rowCells.push(thumbCell);
	if (showProductName) rowCells.push(productNameCell);
	if (showQuantity) rowCells.push(quantityCell);
	if (showUnitPrice) rowCells.push(unitPriceCell);
	if (showLineTotal) rowCells.push(lineTotalCell);
	if (showSku) rowCells.push(skuCell);

	const rowTemplate = rowCells.join('');

	return `
		<div
			id="${data.id}"
			data-type="${PRODUCT_TABLE_NAMESPACE}"
			data-pdfdraft-product-table="1"
			data-pdfdraft-pt-instance="${data.id}"
			data-max-rows="${maxRows}"
			data-row-height-px="${spec.rowHeightPx + gap}"
			data-header-height-px="${spec.headerHeightPx}"
			style="${styleAttr};overflow:hidden"
		>
			${zebraStyle}
			<div class="pdfdraft-pt-mz-inner">
			<table>
				<colgroup>${colgroupParts.join('')}</colgroup>
				<thead>
					<tr style="height:${spec.headerHeightPx}px">${hThumb}${hProduct}${hQty}${hUnit}${hTotal}${hSku}</tr>
				</thead>
				<tbody>
					<tr style="height:${spec.rowHeightPx}px">${rowTemplate}</tr>
				</tbody>
			</table>
			</div>
		</div>
	`;
}

export function productTableToHTML(data: any): string {
	const props = {
		...DEFAULT_PRODUCT_TABLE_TEMPLATE_SETTINGS,
		...(data.props ?? {}),
		columns: {
			...DEFAULT_PRODUCT_TABLE_TEMPLATE_SETTINGS.columns,
			...(data.props?.columns ?? {}),
		},
		textStyle: {
			...(DEFAULT_PRODUCT_TABLE_TEMPLATE_SETTINGS.textStyle ?? {}),
			...(data.props?.textStyle ?? {}),
		},
	} as ProductTableTemplateSettings;
	const spec = getTemplateSpec(props);

	let showProductName = Boolean(props.columns?.showProductName);
	let showQuantity = Boolean(props.columns?.showQuantity);
	let showUnitPrice = Boolean(props.columns?.showUnitPrice);
	let showLineTotal = Boolean(props.columns?.showLineTotal);
	const showSku = Boolean(props.columns?.showSku);
	const showThumbnail = Boolean(props.columns?.showThumbnail);
	const textStyle = props.textStyle ?? {};

	const textAlign = textStyle.textAlign ?? 'left';
	const fontFamily = textStyle.fontFamily;
	const fontWeight = textStyle.fontWeight;
	const textColor = textStyle.color;
	const headerTextColor =
		props.headerTextColor && props.headerTextColor.trim() !== ''
			? props.headerTextColor
			: textColor;

	const rawHeight = data.style?.height ?? data.props?.style?.height ?? data.style?.maxHeight;
	const heightPx = toPx(rawHeight) ?? (spec.headerHeightPx + spec.rowHeightPx * 5);

	const rowsThatFit = Math.max(
		1,
		Math.floor((heightPx - spec.headerHeightPx) / (spec.rowHeightPx + (spec.rowGapPx ?? 0))),
	);

	const maxRows = rowsThatFit;

	const style = styleGenerator.generateElementStyle(data.style);

	let visibleColumnCount = [
		showProductName,
		showQuantity,
		showUnitPrice,
		showLineTotal,
		showSku,
		showThumbnail,
	].filter(Boolean).length;

	if (visibleColumnCount === 0) {
		showProductName = true;
		visibleColumnCount = 1;
	}

	const elementWidthPx =
		toPx(data.style?.width ?? data.props?.style?.width) ??
		undefined;
	const tableWidthCss = elementWidthPx ? `${elementWidthPx}px` : 'auto';

	if (spec.modernZebra) {
		return buildModernZebraTableHtml({
			data,
			props,
			spec,
			showThumbnail,
			showProductName,
			showQuantity,
			showUnitPrice,
			showLineTotal,
			showSku,
			textStyle,
			maxRows,
			styleAttr: style,
			elementWidthPx,
		});
	}

	const baseCol = 100 / visibleColumnCount;
	const cellBorder = `${spec.borderWidthPx}px solid ${spec.borderColor}`;

	const effectiveHeaderBg =
		props.headerBackgroundColor && props.headerBackgroundColor.trim() !== ''
			? props.headerBackgroundColor
			: spec.headerBg;

	const tableCss = [
		`width:${tableWidthCss}`,
		'height:100%',
		'border-collapse:collapse',
		'table-layout:fixed',
		`font-size:${spec.fontSizePx}px`,
		`line-height:${spec.lineHeight}`,
	].join(';');

	const cellCss = [
		`border:${cellBorder}`,
		`padding:${spec.cellPaddingPx}px`,
		'vertical-align:top',
		'word-wrap:break-word',
		`text-align:${textAlign}`,
		'overflow:hidden',
		textColor ? `color:${textColor}` : '',
		fontFamily ? `font-family:${fontFamily}` : '',
		fontWeight != null ? `font-weight:${fontWeight}` : '',
	].join(';');

	const headerCss = [
		cellCss,
		`background:${effectiveHeaderBg}`,
		headerTextColor ? `color:${headerTextColor}` : '',
		`font-weight:${spec.headerFontWeight}`,
	].join(';');

	const headerCells: string[] = [];
	if (showThumbnail)
		headerCells.push(
			`<th style="${headerCss};height:${spec.headerHeightPx}px">Thumbnail</th>`,
		);
	if (showProductName)
		headerCells.push(
			`<th style="${headerCss};height:${spec.headerHeightPx}px">Product Name</th>`,
		);
	if (showQuantity)
		headerCells.push(
			`<th style="${headerCss};height:${spec.headerHeightPx}px">Quantity</th>`,
		);
	if (showUnitPrice)
		headerCells.push(
			`<th style="${headerCss};height:${spec.headerHeightPx}px">Price (Unit Price)</th>`,
		);
	if (showLineTotal)
		headerCells.push(
			`<th style="${headerCss};height:${spec.headerHeightPx}px">Total (line total)</th>`,
		);
	if (showSku)
		headerCells.push(
			`<th style="${headerCss};height:${spec.headerHeightPx}px">SKU</th>`,
		);

	const productNameCell = `<td style="${cellCss};height:${spec.rowHeightPx}px"><div style="width:100%;">{{item.product_display_name}}</div></td>`;
	const quantityCell = `<td style="${cellCss};height:${spec.rowHeightPx}px"><div style="width:100%;">{{item.quantity}}</div></td>`;
	const unitPriceCell = `<td style="${cellCss};height:${spec.rowHeightPx}px"><div style="width:100%;">{{item.unit_price}}</div></td>`;
	const lineTotalCell = `<td style="${cellCss};height:${spec.rowHeightPx}px"><div style="width:100%;">{{item.line_total}}</div></td>`;

	const skuCell = `<td style="${cellCss};height:${spec.rowHeightPx}px"><div style="width:100%;">{{item.sku}}</div></td>`;
	const thumbCell = `<td style="${cellCss};height:${spec.rowHeightPx}px"><div style="width:${spec.thumbnailSizePx}px;height:${spec.thumbnailSizePx}px;overflow:hidden;">{{item.product_image}}</div></td>`;

	const rowCells: string[] = [];
	if (showThumbnail) rowCells.push(thumbCell);
	if (showProductName) rowCells.push(productNameCell);
	if (showQuantity) rowCells.push(quantityCell);
	if (showUnitPrice) rowCells.push(unitPriceCell);
	if (showLineTotal) rowCells.push(lineTotalCell);
	if (showSku) rowCells.push(skuCell);

	const rowTemplate = rowCells.join('');

	const colgroupParts: string[] = [];
	if (showThumbnail) colgroupParts.push(`<col style="width:${baseCol}%"/>`);
	if (showProductName) colgroupParts.push(`<col style="width:${baseCol}%"/>`);
	if (showQuantity) colgroupParts.push(`<col style="width:${baseCol}%"/>`);
	if (showUnitPrice) colgroupParts.push(`<col style="width:${baseCol}%"/>`);
	if (showLineTotal) colgroupParts.push(`<col style="width:${baseCol}%"/>`);
	if (showSku) colgroupParts.push(`<col style="width:${baseCol}%"/>`);

	return `
		<div
			id="${data.id}"
			data-type="${PRODUCT_TABLE_NAMESPACE}"
			data-pdfdraft-product-table="1"
			data-max-rows="${maxRows}"
			data-row-height-px="${spec.rowHeightPx}"
			data-header-height-px="${spec.headerHeightPx}"
			style="${style};overflow:hidden"
		>
			<table style="${tableCss}">
				<colgroup>${colgroupParts.join('')}</colgroup>
				<thead>
					<tr style="height:${spec.headerHeightPx}px">${headerCells.join('')}</tr>
				</thead>
				<tbody>
					<tr style="height:${spec.rowHeightPx}px">${rowTemplate}</tr>
				</tbody>
			</table>
		</div>
	`;
}
