// The actual receipt — the star of the show.

const CURRENCY_SYMBOL = { USD: "$", EUR: "€", RUB: "₽", GBP: "£" };

// Crypto assets — value is the option key. Each carries display + QR payload format.
const CRYPTO_ASSETS = [
  { value: "btc",       ticker: "BTC",  network: "Bitcoin",        scheme: "bitcoin:"   },
  { value: "eth",       ticker: "ETH",  network: "Ethereum",       scheme: "ethereum:"  },
  { value: "usdt-erc20",ticker: "USDT", network: "ERC-20 · Ethereum", scheme: "" },
  { value: "usdt-trc20",ticker: "USDT", network: "TRC-20 · Tron",   scheme: "" },
  { value: "usdt-bep20",ticker: "USDT", network: "BEP-20 · BSC",    scheme: "" },
  { value: "usdc-erc20",ticker: "USDC", network: "ERC-20 · Ethereum", scheme: "" },
  { value: "usdc-sol",  ticker: "USDC", network: "Solana",          scheme: "" },
  { value: "usdc-base", ticker: "USDC", network: "Base",            scheme: "" },
];

function cryptoMeta(value) {
  return CRYPTO_ASSETS.find((a) => a.value === value) || CRYPTO_ASSETS[0];
}

// Basic, conservative address validators — pattern + length only.
const VALIDATORS = {
  btc: (a) =>
    /^(bc1[a-z0-9]{8,87}|[13][a-km-zA-HJ-NP-Z1-9]{25,39})$/.test(a),
  eth: (a) => /^0x[a-fA-F0-9]{40}$/.test(a),
  tron: (a) => /^T[1-9A-HJ-NP-Za-km-z]{33}$/.test(a),
  solana: (a) => /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(a),
};

const ASSET_VALIDATOR = {
  "btc": "btc",
  "eth": "eth",
  "usdt-erc20": "eth",
  "usdt-trc20": "tron",
  "usdt-bep20": "eth",
  "usdc-erc20": "eth",
  "usdc-sol": "solana",
  "usdc-base": "eth",
};

function validateCryptoAddress(asset, address) {
  if (!address) return { ok: null, msg: "" };
  const key = ASSET_VALIDATOR[asset];
  const v = VALIDATORS[key];
  if (!v) return { ok: null, msg: "" };
  return v(address.trim())
    ? { ok: true, msg: "Address looks valid" }
    : { ok: false, msg: "Doesn't match the expected format for this network" };
}

function fmtAmount(n, cur) {
  const sym = CURRENCY_SYMBOL[cur] || "$";
  const v = Number.isFinite(n) ? n : 0;
  return v.toFixed(2) + sym;
}

function fmtDate(iso) {
  if (!iso) return "";
  // YYYY-MM-DD → DD.MM.YY
  const [y, m, d] = iso.split("-");
  if (!y) return iso;
  return `${d}.${m}.${y.slice(2)}`;
}

function generatedStamp() {
  const d = new Date();
  const p = (n) => String(n).padStart(2, "0");
  return `${p(d.getDate())}.${p(d.getMonth() + 1)}.${String(d.getFullYear()).slice(2)} ${p(d.getHours())}:${p(d.getMinutes())}`;
}

function lineItemTotal(it) {
  if (it.rateType === "hourly") {
    const h = parseFloat(it.hours) || 0;
    const r = parseFloat(it.rate) || 0;
    return h * r;
  }
  return parseFloat(it.total) || 0;
}

// Dashed divider — uses real CSS so it scales with width
function Divider({ style = "dashed" }) {
  return (
    <div
      className="my-2.5"
      style={{
        borderTop: `1px ${style} #111`,
        opacity: style === "dashed" ? 0.55 : 0.9,
      }}
    />
  );
}

function Pill({ children }) {
  // html2canvas mis-aligns text vs. background in inline-block when line-height
  // doesn't match the font's natural ascent. inline-flex with align-items:center
  // bypasses baseline math entirely — flex centers the text geometrically inside
  // the box, so CSS and html2canvas render identically.
  return (
    <span
      style={{
        display: "inline-flex",
        alignItems: "center",
        justifyContent: "center",
        background: "#171717",
        color: "white",
        fontSize: "10px",
        letterSpacing: "0.1em",
        fontWeight: 500,
        height: "18px",
        paddingLeft: "6px",
        paddingRight: "7px", // +1px absorbs letter-spacing tail
        verticalAlign: "middle",
        whiteSpace: "nowrap",
        lineHeight: 1,
      }}
    >
      {children}
    </span>
  );
}

function LineItem({ idx, item, currency }) {
  const total = lineItemTotal(item);
  const num = String(idx + 1).padStart(2, "0");
  const showDetail =
    item.rateType === "hourly" &&
    (parseFloat(item.hours) > 0 || parseFloat(item.rate) > 0);

  return (
    <div className="text-[13px] leading-[1.55]">
      {/* Title row */}
      <div className="flex items-start gap-2">
        <span className="text-neutral-900">{num}.</span>
        <span className="flex-1 uppercase tracking-[0.04em] font-medium break-words">
          {item.title || "UNTITLED"}
        </span>
        {item.label && <Pill>{item.label.toUpperCase()}</Pill>}
      </div>

      {/* Description */}
      {item.description && (
        <div className="pl-7 pr-1 mt-1 text-[12px] text-neutral-700 whitespace-pre-wrap break-words">
          {item.description}
        </div>
      )}

      {/* Meta row: date / qty / total */}
      <div className="pl-7 mt-1 flex items-baseline justify-between gap-2">
        <div className="text-[12px] text-neutral-600 tabular-nums">
          {showDetail ? (
            <span>
              {parseFloat(item.hours) || 0}h × {fmtAmount(parseFloat(item.rate) || 0, currency)}
            </span>
          ) : (
            <span>{fmtDate(item.date)}</span>
          )}
        </div>
        <div className="text-[13px] font-medium tabular-nums">
          {fmtAmount(total, currency)}
        </div>
      </div>
    </div>
  );
}

function Receipt({ data, theme = "paper", t = (k) => k }) {
  const {
    order, date, client, from, note, currency, items, taxPct,
    paymentType, paymentUrl, cryptoAsset, cryptoAddress,
    discountType, discountValue, taxOrder,
  } = data;

  const subtotal = items.reduce((s, it) => s + lineItemTotal(it), 0);
  const discount =
    discountType === "percent"
      ? (subtotal * (parseFloat(discountValue) || 0)) / 100
      : parseFloat(discountValue) || 0;
  const taxBase =
    taxOrder === "before" ? subtotal : Math.max(0, subtotal - discount);
  const tax = (taxBase * (parseFloat(taxPct) || 0)) / 100;
  const total = Math.max(0, subtotal - discount) + tax;

  const bg = theme === "cream" ? "#FAFAF7" : "#FFFFFF";

  return (
    <div
      className="relative receipt-shell"
      style={{ width: 420, margin: "0 auto", maxWidth: "100%" }}
    >
      {/* On viewports narrower than the receipt, scale the whole thing down
          uniformly so internal layout (barcode, QR, torn edge) stays pixel-
          perfect. Set --rcpt-scale from a parent media query / inline. */}
      <style>{`
        @media (max-width: 460px) {
          .receipt-shell {
            transform: scale(calc((100vw - 24px) / 420));
            transform-origin: top center;
            margin-bottom: calc((1 - (100vw - 24px) / 420) * -100%) !important;
          }
        }
      `}</style>
      <div
        id="receipt-print"
        className="relative font-mono text-neutral-900"
        style={{
          background: bg,
          padding: "32px 28px 12px",
          boxShadow: "0 1px 2px rgba(0,0,0,0.04), 0 12px 32px -16px rgba(0,0,0,0.18)",
          backgroundImage:
            "radial-gradient(circle at 1px 1px, rgba(0,0,0,0.025) 1px, transparent 0)",
          backgroundSize: "3px 3px",
        }}
      >
        {/* Header */}
        <div className="text-center">
          <div className="text-[16px] mb-3 tracking-[0.05em]" aria-hidden>
            <span>※</span>
          </div>
          <div className="text-[22px] font-semibold tracking-[0.32em] uppercase">
            {t("r_receipt")}
          </div>
          {from && (
            <div className="text-[12px] mt-2 tracking-[0.18em] uppercase text-neutral-900">
              {from}
            </div>
          )}
          <div className="text-[10px] mt-1 tracking-[0.2em] uppercase text-neutral-500">
            {t("r_no")}{order || "0000"}
          </div>
        </div>

        <Divider />

        {/* Meta */}
        <div className="text-[12px] leading-[1.7] tabular-nums">
          <MetaRow k={t("r_order")} v={`#${order || "0000"}`} />
          <MetaRow k={t("r_date")} v={fmtDate(date)} />
          {client && <MetaRow k={t("r_client")} v={client.toUpperCase()} />}
          <MetaRow k={t("r_currency")} v={currency} />
        </div>

        <Divider />

        {/* Column headers */}
        <div className="flex justify-between text-[10px] tracking-[0.18em] uppercase text-neutral-500">
          <span>{t("r_item")}</span>
          <span>{t("r_amount")}</span>
        </div>
        <Divider />

        {/* Line items */}
        <div className="space-y-4">
          {items.map((it, i) => (
            <LineItem key={it.id} idx={i} item={it} currency={currency} />
          ))}
        </div>

        <Divider />

        {/* Totals */}
        <div className="text-[12px] leading-[1.8] tabular-nums">
          <TotalRow k={t("r_subtotal")} v={fmtAmount(subtotal, currency)} />
          {taxOrder === "before" && parseFloat(taxPct) > 0 && (
            <TotalRow k={`${t("r_tax")} (${taxPct}%)`} v={fmtAmount(tax, currency)} />
          )}
          {discount > 0 && (
            <TotalRow
              k={`${t("r_discount")}${discountType === "percent" ? ` (${discountValue}%)` : ""}`}
              v={"− " + fmtAmount(discount, currency)}
            />
          )}
          {taxOrder !== "before" && parseFloat(taxPct) > 0 && (
            <TotalRow k={`${t("r_tax")} (${taxPct}%)`} v={fmtAmount(tax, currency)} />
          )}
          <div
            className="flex justify-between mt-1 pt-1 text-[15px] font-semibold uppercase"
            style={{ borderTop: "1px solid #111" }}
          >
            <span>{t("r_total")}</span>
            <span>{fmtAmount(total, currency)}</span>
          </div>
        </div>

        <Divider />

        {/* Note */}
        {note && (
          <>
            <div className="text-[11px] text-center leading-[1.6] uppercase tracking-[0.08em] whitespace-pre-wrap">
              {note}
            </div>
            <Divider />
          </>
        )}

        {/* Payment */}
        <PaymentBlock
          paymentType={paymentType}
          paymentUrl={paymentUrl}
          cryptoAsset={cryptoAsset}
          cryptoAddress={cryptoAddress}
          t={t}
        />

        {/* Footer */}
        <div className="text-center pt-1 pb-2">
          <div className="text-[10px] text-neutral-500 tracking-[0.18em]">
            * * *
          </div>
          <div className="text-[10px] mt-3 text-neutral-500 tracking-[0.18em]">
            {t("r_generated")} {generatedStamp()}
          </div>
        </div>

        {/* Barcode */}
        <div className="mt-3 mb-1 flex justify-center">
          <Barcode seed={(order || "0000") + total.toFixed(2)} />
        </div>
        <div className="text-center text-[9px] tracking-[0.3em] text-neutral-500">
          {(order || "0000")}-{Math.round(total * 100)}
        </div>
      </div>

      {/* Torn bottom edge */}
      <TornEdge color={bg} />

      {/* Scissors guide */}
      <div className="mt-4 flex items-center gap-2 text-neutral-400 text-[11px] tracking-[0.18em] uppercase font-mono">
        <Scissors />
        <div className="flex-1 border-t border-dashed border-neutral-400" />
        <span>{t("r_cut_here")}</span>
        <div className="flex-1 border-t border-dashed border-neutral-400" />
      </div>
    </div>
  );
}

function MetaRow({ k, v }) {
  return (
    <div className="flex justify-between">
      <span className="text-neutral-500">{k}</span>
      <span>{v}</span>
    </div>
  );
}

function TotalRow({ k, v }) {
  return (
    <div className="flex justify-between">
      <span className="text-neutral-600 uppercase tracking-[0.06em]">{k}</span>
      <span>{v}</span>
    </div>
  );
}

// Random-but-deterministic vertical bar barcode
function Barcode({ seed = "" }) {
  let h = 0;
  for (let i = 0; i < seed.length; i++) h = (h * 31 + seed.charCodeAt(i)) >>> 0;
  const bars = [];
  for (let i = 0; i < 48; i++) {
    h = (h * 1664525 + 1013904223) >>> 0;
    const w = (h & 3) + 1; // 1..4 px
    const black = (h & 4) !== 0;
    bars.push({ w, black });
  }
  return (
    <div className="flex items-end gap-[1px] h-8">
      {bars.map((b, i) => (
        <div
          key={i}
          style={{
            width: b.w,
            height: "100%",
            background: b.black ? "#111" : "transparent",
          }}
        />
      ))}
    </div>
  );
}

function TornEdge({ color }) {
  // SVG zig-zag bottom that matches the paper color
  const pts = [];
  const teeth = 22;
  const w = 420;
  const tooth = w / teeth;
  for (let i = 0; i <= teeth; i++) {
    const x = i * tooth;
    const y = i % 2 === 0 ? 0 : 10;
    pts.push(`${x},${y}`);
  }
  return (
    <svg
      width={w}
      height={11}
      viewBox={`0 0 ${w} 11`}
      style={{ display: "block", marginTop: -1 }}
    >
      <polygon
        points={`0,0 ${pts.join(" ")} ${w},0`}
        fill={color}
        style={{ filter: "drop-shadow(0 8px 16px rgba(0,0,0,0.08))" }}
      />
    </svg>
  );
}

function Scissors() {
  return (
    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6">
      <circle cx="6" cy="6" r="3" />
      <circle cx="6" cy="18" r="3" />
      <path d="M20 4L8.12 15.88" />
      <path d="M14.47 14.47L20 20" />
      <path d="M8.12 8.12L12 12" />
    </svg>
  );
}

// QR code rendered as inline SVG using qrcode-generator
function QrSvg({ text, size = 140 }) {
  if (!text || !window.qrcode) {
    return (
      <div
        style={{
          width: size,
          height: size,
          border: "1px dashed #111",
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          fontSize: 10,
          letterSpacing: "0.18em",
          color: "#666",
          textTransform: "uppercase",
        }}
      >
        QR
      </div>
    );
  }
  // Auto type number, medium ECC
  const qr = window.qrcode(0, "M");
  qr.addData(text);
  qr.make();
  const count = qr.getModuleCount();
  const cell = size / count;
  const rects = [];
  for (let r = 0; r < count; r++) {
    for (let c = 0; c < count; c++) {
      if (qr.isDark(r, c)) {
        rects.push(
          <rect
            key={`${r}-${c}`}
            x={c * cell}
            y={r * cell}
            width={cell + 0.5}
            height={cell + 0.5}
            fill="#111"
          />
        );
      }
    }
  }
  return (
    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} shapeRendering="crispEdges">
      <rect width={size} height={size} fill="transparent" />
      {rects}
    </svg>
  );
}

function truncMiddle(s, head = 8, tail = 8) {
  if (!s) return "";
  if (s.length <= head + tail + 3) return s;
  return s.slice(0, head) + "…" + s.slice(-tail);
}

function PaymentBlock({ paymentType, paymentUrl, cryptoAsset, cryptoAddress, t = (k) => k }) {
  if (paymentType === "link" && paymentUrl) {
    return (
      <>
        <div className="text-center">
          <a
            href={paymentUrl}
            target="_blank"
            rel="noopener noreferrer"
            className="inline-flex items-center justify-center w-full h-11 bg-neutral-900 text-white text-[13px] uppercase font-semibold hover:bg-neutral-800 transition-colors"
            style={{ letterSpacing: "0.28em", paddingRight: "4px" /* absorb letter-spacing tail for html2canvas */ }}
          >
            ▸ {t("r_pay_now")} ◂
          </a>
          <div className="mt-2 text-[10px] text-neutral-500 break-all tracking-[0.02em]">
            {paymentUrl.replace(/^https?:\/\//, "")}
          </div>
          <div className="mt-3 flex justify-center">
            <QrSvg text={paymentUrl} size={110} />
          </div>
          <div className="mt-2 text-[9px] tracking-[0.18em] uppercase text-neutral-500">
            {t("r_scan_to_pay")}
          </div>
        </div>
        <Divider />
      </>
    );
  }

  if (paymentType === "crypto" && cryptoAddress) {
    const meta = cryptoMeta(cryptoAsset);
    const payload = meta.scheme ? meta.scheme + cryptoAddress : cryptoAddress;
    return (
      <>
        <div className="text-center">
          <div className="text-[18px] font-semibold tracking-[0.18em]">
            {meta.ticker}
          </div>
          <div
            className="mt-1"
            style={{
              display: "inline-flex",
              alignItems: "center",
              justifyContent: "center",
              background: "#171717",
              color: "white",
              fontSize: "9px",
              letterSpacing: "0.16em",
              textTransform: "uppercase",
              fontWeight: 500,
              height: "20px",
              paddingLeft: "8px",
              paddingRight: "9px",
              whiteSpace: "nowrap",
              lineHeight: 1,
            }}
          >
            {meta.network}
          </div>

          <div className="mt-3 flex justify-center">
            <div style={{ padding: 8, background: "#fff", border: "1px solid #111" }}>
              <QrSvg text={payload} size={140} />
            </div>
          </div>

          <div className="mt-3 text-[10px] tracking-[0.02em] break-all leading-snug px-2">
            {cryptoAddress}
          </div>
          <div className="mt-2 text-[9px] tracking-[0.18em] uppercase text-neutral-500">
            {t("r_scan_or_copy")}
          </div>
        </div>
        <Divider />
      </>
    );
  }

  return null;
}

// Plain-text version for copy-to-clipboard
function receiptAsText(data, t = (k) => k) {
  const { order, date, client, note, currency, items, taxPct, discountType, discountValue, taxOrder } = data;
  const sym = CURRENCY_SYMBOL[currency] || "$";
  const W = 36;
  const line = (s = "-") => s.repeat(W);
  const pad = (l, r) => {
    const space = Math.max(1, W - l.length - r.length);
    return l + " ".repeat(space) + r;
  };
  const center = (s) => {
    const pad = Math.max(0, Math.floor((W - s.length) / 2));
    return " ".repeat(pad) + s;
  };

  const subtotal = items.reduce((s, it) => s + lineItemTotal(it), 0);
  const discount =
    discountType === "percent"
      ? (subtotal * (parseFloat(discountValue) || 0)) / 100
      : parseFloat(discountValue) || 0;
  const taxBase =
    taxOrder === "before" ? subtotal : Math.max(0, subtotal - discount);
  const tax = (taxBase * (parseFloat(taxPct) || 0)) / 100;
  const total = Math.max(0, subtotal - discount) + tax;

  const lines = [];
  lines.push(line());
  lines.push(center(t("r_receipt")));
  if (data.from) lines.push(center(data.from.toUpperCase()));
  lines.push(line());
  lines.push(pad(t("r_order") + ":", "#" + (order || "0000")));
  lines.push(pad(t("r_date") + ":", fmtDate(date)));
  if (client) lines.push(pad(t("r_client") + ":", client.toUpperCase()));
  lines.push(pad(t("r_currency") + ":", currency));
  lines.push(line());

  items.forEach((it, i) => {
    const num = String(i + 1).padStart(2, "0");
    const titleLine = `${num}. ${(it.title || t("item_untitled")).toUpperCase()}${it.label ? "  [" + it.label.toUpperCase() + "]" : ""}`;
    lines.push(titleLine);
    if (it.description) {
      it.description.split("\n").forEach((l) => lines.push("    " + l));
    }
    const tot = lineItemTotal(it).toFixed(2) + sym;
    if (it.rateType === "hourly") {
      const h = (parseFloat(it.hours) || 0) + "h";
      const r = (parseFloat(it.rate) || 0).toFixed(2) + sym;
      lines.push(pad(`    ${fmtDate(it.date)}  ${h} \u00d7 ${r}`, tot));
    } else {
      lines.push(pad(`    ${fmtDate(it.date)}`, tot));
    }
    lines.push("");
  });

  lines.push(line());
  lines.push(pad(t("r_subtotal"), subtotal.toFixed(2) + sym));
  if (taxOrder === "before" && parseFloat(taxPct) > 0)
    lines.push(pad(`${t("r_tax")} (${taxPct}%)`, tax.toFixed(2) + sym));
  if (discount > 0) {
    const dlabel = t("r_discount") + (discountType === "percent" ? ` (${discountValue}%)` : "");
    lines.push(pad(dlabel, "-" + discount.toFixed(2) + sym));
  }
  if (taxOrder !== "before" && parseFloat(taxPct) > 0)
    lines.push(pad(`${t("r_tax")} (${taxPct}%)`, tax.toFixed(2) + sym));
  lines.push(pad(t("r_total"), total.toFixed(2) + sym));
  lines.push(line());
  if (note) {
    lines.push("");
    note.split("\n").forEach((l) => lines.push("  " + l));
    lines.push("");
  }
  if (data.paymentType === "link" && data.paymentUrl) {
    lines.push("  " + t("r_pay_now").toUpperCase() + ":");
    lines.push("  " + data.paymentUrl);
    lines.push("");
  } else if (data.paymentType === "crypto" && data.cryptoAddress) {
    const meta = cryptoMeta(data.cryptoAsset);
    lines.push(`  ${meta.ticker} (${meta.network}):`);
    lines.push("  " + data.cryptoAddress);
    lines.push("");
  }
  lines.push(center("* * *"));
  lines.push(center(t("r_generated") + " " + generatedStamp()));
  return lines.join("\n");
}

Object.assign(window, {
  Receipt, receiptAsText, lineItemTotal, fmtAmount, fmtDate, CURRENCY_SYMBOL,
  CRYPTO_ASSETS, validateCryptoAddress,
});
