// ── Theme → CloverElementStyles compiler ────────────────────────
//
// Translates the high-level `CloverFieldTheme` config into the JSON shape
// Clover's `elements.create()` expects.
//
// Clover honors per-element selectors (`card-number input`) reliably; global
// selectors like `'::placeholder'` are inconsistently applied across Clover
// versions. We emit per-element rules for every field so styling is
// deterministic. The `'input'` global rule is still emitted as a baseline.
//
// Key invariants the legacy plugin established (mirrored here so the visual
// output matches what merchants are already used to):
//   - Input fills its iframe: height: 100%, width: 100%, no padding/margin.
//   - Card number + cardholder name + email get a left text-indent so the
//     placeholder doesn't sit flush against the iframe edge.
//   - Date / CVV / postal-code text is centered.

import type { CloverCssProperties, CloverElementStyles, CloverFieldTheme } from './types';

const PLACEHOLDER_PSEUDOS = [
  '::placeholder',
  '::-webkit-input-placeholder',
  '::-moz-placeholder',
  ':-ms-input-placeholder',
  ':-moz-placeholder',
] as const;

// Clover's element-scoped CSS selector is the lower-kebab form of the element
// type name. `CARD_EMAIL_ADDRESS` is `card-email-address`, NOT `card-email` —
// the short form is silently ignored (verified via discovery 2026-05-18). The
// legacy WP plugin had the same bug, which is why the email placeholder sat
// flush against the iframe edge while the name field was indented correctly.
const LEFT_ALIGNED_FIELDS = ['card-number', 'card-name', 'card-email-address'] as const;
const CENTER_ALIGNED_FIELDS = ['card-date', 'card-cvv', 'card-postal-code'] as const;

export function compileTheme(theme?: CloverFieldTheme): CloverElementStyles {
  const styles: CloverElementStyles = {};

  // ── Global input baseline. Applies to every Clover element's input. ──
  //
  // `height` must be a definite length, not `100%`. The Clover iframe document's
  // `<html>`/`<body>` don't have an explicit height, so `100%` resolves to the
  // input's content-box height (~17px) and clicks on the rest of the 46px
  // wrapper land on the iframe body instead of the input. Matching the wrapper
  // height in `styles.ts` (46px) keeps the entire wrapper clickable; the
  // `overflow: hidden` on `.wcp-pf__field` absorbs any sub-pixel overshoot.
  // `lineHeight` matches so text is vertically centered without depending on
  // flex/grid we don't control inside the iframe. `border: 'none'` suppresses
  // Clover's default input border — the SDK's wrapper owns the border.
  const inputHeight = theme?.inputHeight ?? '46px';
  styles.input = stripUndefined<CloverCssProperties>({
    padding: '0',
    margin: '0',
    border: 'none',
    height: inputHeight,
    width: '100%',
    lineHeight: inputHeight,
    fontFamily: theme?.fontFamily,
    fontSize: theme?.fontSize,
    color: theme?.textColor,
  });

  // ── Per-element input rules: text position. ──
  for (const field of LEFT_ALIGNED_FIELDS) {
    styles[`${field} input`] = {
      textAlign: 'left',
      textIndent: '14px',
    };
  }
  for (const field of CENTER_ALIGNED_FIELDS) {
    styles[`${field} input`] = {
      textAlign: 'center',
    };
  }

  // ── Per-element placeholder rules: color only (alignment inherits from input). ──
  if (theme?.placeholderColor) {
    for (const pseudo of PLACEHOLDER_PSEUDOS) {
      for (const field of [...LEFT_ALIGNED_FIELDS, ...CENTER_ALIGNED_FIELDS]) {
        styles[`${field} input${pseudo}`] = { color: theme.placeholderColor };
      }
    }
  }

  // ── User overrides win over compiled defaults. ──
  if (theme?.overrides) {
    Object.assign(styles, theme.overrides);
  }
  return styles;
}

function stripUndefined<T extends object>(obj: T): Partial<T> {
  const out: Partial<T> = {};
  for (const [k, v] of Object.entries(obj)) {
    if (v !== undefined) {
      (out as Record<string, unknown>)[k] = v;
    }
  }
  return out;
}
