import type { ShareMetadata } from './share';

export interface CardSize { width: number; height: number }
export interface CardRect { x: number; y: number; width: number; height: number }
export const CARD = { width: 1080, height: 1920 } as const;
export const CARD_SIZES = { story: CARD, post: { width: 1080, height: 1350 } } as const;

/** Reserve the paper caption from the bottom, then give the photo all remaining space. */
export function cardLayout({ width, height }: CardSize) {
  if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) throw new Error('invalid canvas dimensions');
  const scale = Math.min(width / 1080, height / 1350);
  const rect = (x: number, y: number, w: number, h: number): CardRect => ({ x: x * scale, y, width: w * scale, height: h * scale });
  const margin = 44 * scale, inset = 72 * scale;
  const strip = { x: margin, y: height - 152 * scale, width: width - 2 * margin, height: 100 * scale };
  // 110px accommodates the eyebrow and two lines without moving any UI over the photo.
  const tag = rect(72, strip.y - 150 * scale, 520, 110);
  const chips = [rect(width / scale - 456, tag.y + 13 * scale, 194, 84), rect(width / scale - 246, tag.y + 13 * scale, 174, 84)];
  const caption = { x: inset, y: tag.y - 114 * scale, width: width - 2 * inset, height: 88 * scale };
  const photo = { x: margin, y: margin, width: width - 2 * margin, height: caption.y - 44 * scale - margin };
  const watermark = rect(width / scale - 224, height - 42 * scale, 200, 30);
  return { scale, photo, caption, tag, chips, strip, watermark };
}

/** Whole source image, one uniform fit scale, no source crop or person detection. */
export function fitPhoto(image: HTMLImageElement, window: CardRect): CardRect {
  const iw = image.naturalWidth || image.width, ih = image.naturalHeight || image.height;
  if (iw <= 0 || ih <= 0) throw new Error('invalid image dimensions');
  const scale = Math.min(window.width / iw, window.height / ih);
  const width = iw * scale, height = ih * scale;
  return { x: window.x + (window.width - width) / 2, y: window.y + (window.height - height) / 2, width, height };
}
const FONT = '"Helvetica Neue", Helvetica, Arial, sans-serif';
const normal = (text: string) => text.trim().replace(/\s+/g, ' ');

function width(ctx: CanvasRenderingContext2D, text: string, spacing = 0): number {
  return ctx.measureText(text).width + Math.max(0, Array.from(text).length - 1) * spacing;
}
export function fitText(ctx: CanvasRenderingContext2D, text: string, max: number, spacing = 0): string {
  if (width(ctx, text, spacing) <= max) return text;
  const chars = Array.from(text);
  while (chars.length && width(ctx, chars.join('') + '…', spacing) > max) chars.pop();
  return chars.join('').trimEnd() + '…';
}
export function wrapTwoLines(ctx: CanvasRenderingContext2D, value: string, max: number): string[] {
  const words = normal(value).split(' ');
  let first = '';
  while (words.length && width(ctx, [first, words[0]].filter(Boolean).join(' ')) <= max) {
    first = [first, words.shift()].filter(Boolean).join(' ');
  }
  if (!first) return [fitText(ctx, words.join(' '), max)];
  return words.length ? [first, fitText(ctx, words.join(' '), max)] : [first];
}
export function drawSpacedText(ctx: CanvasRenderingContext2D, text: string, x: number, y: number, spacing: number): void {
  if (typeof ctx.letterSpacing === 'string') {
    const spaced = ctx as CanvasRenderingContext2D & { letterSpacing: string };
    spaced.letterSpacing = `${spacing}px`;
    ctx.fillText(text, x, y);
    spaced.letterSpacing = '0px';
  } else {
    for (const glyph of Array.from(text)) {
      ctx.fillText(glyph, x, y);
      x += ctx.measureText(glyph).width + spacing;
    }
  }
}
function rounded(ctx: CanvasRenderingContext2D, x: number, y: number, w: number, h: number, r: number): void {
  ctx.beginPath();
  ctx.roundRect(x, y, w, h, r);
}
function disc(ctx: CanvasRenderingContext2D, x: number, y: number, r: number, color: string): void {
  ctx.fillStyle = color;
  ctx.beginPath(); ctx.arc(x, y, r, 0, Math.PI * 2); ctx.fill();
}
function contain(ctx: CanvasRenderingContext2D, image: HTMLImageElement, window: CardRect): void {
  const r = fitPhoto(image, window);
  ctx.drawImage(image, r.x, r.y, r.width, r.height);
}

export function drawShareCard(ctx: CanvasRenderingContext2D, photo: HTMLImageElement, thumb: HTMLImageElement | null, metadata: ShareMetadata): void {
  const { scale: s, photo: window, caption, tag, chips, strip } = cardLayout(ctx.canvas);
  ctx.save();
  ctx.textAlign = 'left'; ctx.textBaseline = 'top';
  const paper = ctx.createLinearGradient(0, 0, 0, ctx.canvas.height);
  paper.addColorStop(0, '#f8f5f0'); paper.addColorStop(1, '#efe9e1');
  ctx.fillStyle = paper; ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  // Paper fills the letterbox gaps. Do not clip even the corners of the source photo.
  ctx.fillStyle = '#e7e2da';
  rounded(ctx, window.x, window.y, window.width, window.height, 10 * s); ctx.fill();
  contain(ctx, photo, window);

  ctx.font = `800 ${80 * s}px ${FONT}`; ctx.fillStyle = '#161513';
  drawSpacedText(ctx, 'Should I get it?', caption.x, caption.y, -2 * s);
  const item = normal(metadata.itemName), brand = normal(metadata.brandName || '').toUpperCase();
  if (item) {
    const ty = tag.y + (tag.height - 92 * s) / 2;
    const thumbnail = { x: tag.x, y: ty, width: 76 * s, height: 92 * s };
    ctx.save(); rounded(ctx, thumbnail.x, ty, thumbnail.width, thumbnail.height, 14 * s); ctx.clip();
    const tile = ctx.createLinearGradient(tag.x, ty, tag.x + 26 * s, ty + 92 * s);
    tile.addColorStop(0, '#e7e2da'); tile.addColorStop(1, '#cfc7bb');
    ctx.fillStyle = tile; ctx.fillRect(tag.x, ty, thumbnail.width, thumbnail.height);
    if (thumb) contain(ctx, thumb, thumbnail);
    else {
      ctx.save(); ctx.translate(tag.x + 12 * s, ty + 20 * s); ctx.scale(52 * s / 64, 52 * s / 64);
      ctx.beginPath();
      [[22,8],[32,14],[42,8],[58,18],[52,30],[46,27],[46,58],[18,58],[18,27],[12,30],[6,18]].forEach(([x,y], i) => i ? ctx.lineTo(x,y) : ctx.moveTo(x,y));
      ctx.closePath(); ctx.fillStyle = '#a69d8f'; ctx.fill(); ctx.restore();
    }
    ctx.restore();
    const tx = tag.x + 96 * s, max = tag.width - 96 * s;
    ctx.font = `700 ${34 * s}px ${FONT}`;
    const lines = wrapTwoLines(ctx, item, max);
    const textHeight = lines.length * 37.4 * s + (brand ? 30 * s : 0);
    let y = tag.y + (tag.height - textHeight) / 2;
    if (brand) {
      ctx.font = `600 ${20 * s}px ${FONT}`; ctx.fillStyle = '#8a8378';
      drawSpacedText(ctx, fitText(ctx, brand, max, 3.6 * s), tx, y, 3.6 * s); y += 30 * s;
    }
    ctx.font = `700 ${34 * s}px ${FONT}`; ctx.fillStyle = '#161513';
    lines.forEach((line, i) => ctx.fillText(line, tx, y + i * 37.4 * s));
  }
  ctx.textBaseline = 'middle';
  [['❤️', 'yes'], ['😢', 'no']].forEach(([emoji, label], i) => {
    const pill = chips[i], cy = pill.y + pill.height / 2;
    // Inset the stroke so its painted bounds stay inside the chip rect.
    rounded(ctx, pill.x + s, pill.y + s, pill.width - 2 * s, pill.height - 2 * s, 42 * s);
    ctx.fillStyle = '#fff'; ctx.fill(); ctx.lineWidth = 2 * s; ctx.strokeStyle = '#e2dbd0'; ctx.stroke();
    ctx.font = `${40 * s}px "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif`;
    ctx.fillStyle = '#161513'; ctx.fillText(emoji, pill.x + 26 * s, cy);
    ctx.font = `600 ${38 * s}px ${FONT}`; ctx.fillText(label, pill.x + 90 * s, cy);
  });
  rounded(ctx, strip.x, strip.y, strip.width, strip.height, 28 * s); ctx.fillStyle = '#161513'; ctx.fill();
  const sy = strip.y + strip.height / 2, sx = strip.x + 40 * s;
  ctx.font = `400 ${24 * s}px ${FONT}`; ctx.fillStyle = '#b9b2a7'; ctx.fillText('powered by', sx, sy);
  const byWidth = ctx.measureText('powered by').width;
  ctx.font = `700 ${40 * s}px ${FONT}`; ctx.fillStyle = '#fff'; drawSpacedText(ctx, 'aisthetix', sx + byWidth + 8 * s, sy, -.4 * s);
  ctx.font = `600 ${28 * s}px ${FONT}`;
  const cta = 'Try it on your own photo', left = strip.x + strip.width - 40 * s - ctx.measureText(cta).width;
  disc(ctx, left - 18 * s, sy, 11 * s, 'rgba(94,224,138,.25)'); disc(ctx, left - 18 * s, sy, 6 * s, '#5ee08a');
  ctx.fillStyle = '#f2eee8'; ctx.fillText(cta, left, sy);
  ctx.restore();
}

/** Deliberately the final draw: every successful export carries this disclosure on the paper lip. */
export function stampAiGeneratedWatermark(ctx: CanvasRenderingContext2D): void {
  const { scale, watermark } = cardLayout(ctx.canvas);
  ctx.font = `500 ${22 * scale}px ${FONT}`; ctx.fillStyle = 'rgba(22,21,19,.48)';
  ctx.shadowColor = 'transparent'; ctx.shadowBlur = 0; ctx.shadowOffsetY = 0;
  ctx.textAlign = 'right'; ctx.textBaseline = 'bottom';
  ctx.fillText('ai generated', watermark.x + watermark.width, ctx.canvas.height - 16 * scale);
}
