/**
 * Canvas 2D 字幕绘制纯函数
 * ==========================
 *
 * 从 useCanvasSubtitleRenderer 提取的纯绘制逻辑，可被 Hook 和 PNG 生成器复用。
 */

import { readFile, BaseDirectory } from '@tauri-apps/plugin-fs';
import type { AssStyle } from './assGenerator';

// ASS 基础分辨率（与 generateAssContent 一致）
export const PLAY_RES_Y = 1920;

/**
 * Canvas 2D 字体补偿系数
 *
 * 实测对比（fontSize=56, PingFang SC Medium）:
 * - libass/FreeType 实际渲染高度: 43px (比例 0.768)
 * - Canvas 2D/CoreText 实际渲染高度: 54px (比例 0.964)
 * - Canvas 比 libass 大约 26.5%
 *
 * 原因: 两个引擎对相同 fontSize 的 ascent/descent 计算不同。
 * 补偿后确保预览字幕大小与 FFmpeg 压制输出一致。
 */
export const CANVAS_FONT_COMPENSATION = 0.88;

/**
 * 将 ASS 颜色 &HAABBGGRR 转为 Canvas 可用的 rgba CSS 字符串
 * ASS alpha: 00=不透明, FF=透明（与 CSS 相反）
 */
function assColorToRgba(assColor: string): string {
  const clean = assColor.replace(/^&H/i, '').replace(/&$/, '').padStart(8, '0');
  const alpha = parseInt(clean.slice(0, 2), 16);
  const blue = parseInt(clean.slice(2, 4), 16);
  const green = parseInt(clean.slice(4, 6), 16);
  const red = parseInt(clean.slice(6, 8), 16);
  const a = ((255 - alpha) / 255).toFixed(2);
  return `rgba(${red},${green},${blue},${a})`;
}

/**
 * 按容器宽度自动换行（中文按字，英文按词）
 */
function wrapText(
  ctx: CanvasRenderingContext2D,
  text: string,
  maxWidth: number
): string[] {
  const lines: string[] = [];
  const rawLines = text.split(/\\N/g);

  for (const raw of rawLines) {
    let current = '';
    for (const char of raw) {
      const test = current + char;
      const width = ctx.measureText(test).width;
      if (width > maxWidth && current.length > 0) {
        lines.push(current);
        current = char;
      } else {
        current = test;
      }
    }
    if (current.length > 0) {
      lines.push(current);
    }
  }

  return lines.length > 0 ? lines : [''];
}

/**
 * 设置 Canvas 字体
 */
export function setCanvasFont(
  ctx: CanvasRenderingContext2D,
  style: Partial<AssStyle>,
  scale: number,
  compensation: number = CANVAS_FONT_COMPENSATION
): void {
  const fontSize = (style.fontSize ?? 64) * scale * compensation;
  const fontName = style.fontName ?? 'DouyinSansBold, PingFang SC, sans-serif';
  const weight = (style.bold ?? true) ? 'bold' : 'normal';
  const italic = (style.italic ?? false) ? 'italic' : 'normal';
  ctx.font = `${italic} ${weight} ${fontSize}px ${fontName}`;
}

/**
 * 绘制单行文字（描边或背景色块）
 *
 * BorderStyle=1：文字描边（strokeText）
 * BorderStyle=3：通栏直角条背景色块（fillRect），文字居中压在色块上
 */
export function drawTextLine(
  ctx: CanvasRenderingContext2D,
  text: string,
  x: number,
  y: number,
  style: Partial<AssStyle>,
  scale: number,
  canvasWidth: number
): void {
  const primaryColor = assColorToRgba(style.primaryColor ?? '&H00FFFFFF');
  const outlineColor = assColorToRgba(style.outlineColor ?? '&H00000000');
  const backColor = assColorToRgba(style.backColor ?? '&H80000000');
  const borderStyle = style.borderStyle ?? 1;

  ctx.textAlign = 'center';
  ctx.textBaseline = 'alphabetic';

  if (borderStyle === 3) {
    // 背景色块模式 — 绘制贴边直角条（宽度按文字自适应，居中）
    const metrics = ctx.measureText(text);
    const fontSize = (style.fontSize ?? 64) * scale * CANVAS_FONT_COMPENSATION;
    const paddingY = fontSize * 0.15;
    const paddingX = fontSize * 0.4;

    // 使用 actualBoundingBoxAscent/Descent 计算准确的文字高度
    const ascent = metrics.actualBoundingBoxAscent ?? fontSize * 0.72;
    const descent = metrics.actualBoundingBoxDescent ?? fontSize * 0.28;
    const boxHeight = ascent + descent + paddingY * 2;

    // 宽度按文字实际宽度自适应，居中
    const textWidth = metrics.width;
    const boxWidth = textWidth + paddingX * 2;
    const boxX = (canvasWidth - boxWidth) / 2;
    const boxY = y - ascent - paddingY;

    ctx.fillStyle = backColor;
    ctx.fillRect(boxX, boxY, boxWidth, boxHeight);

    ctx.fillStyle = primaryColor;
    ctx.fillText(text, x, y);
  } else {
    // 描边模式
    const outline = (style.outline ?? 2) * scale;
    if (outline > 0) {
      ctx.strokeStyle = outlineColor;
      ctx.lineWidth = outline;
      ctx.lineJoin = 'round';
      ctx.strokeText(text, x, y);
    }
    ctx.fillStyle = primaryColor;
    ctx.fillText(text, x, y);
  }
}

/**
 * 超长文字截断（按最大宽度逐个字符删减，直到能放下）
 */
export function truncateText(
  ctx: CanvasRenderingContext2D,
  text: string,
  maxWidth: number
): string {
  if (ctx.measureText(text).width <= maxWidth) {return text;}
  let result = text;
  while (result.length > 0 && ctx.measureText(result).width > maxWidth) {
    result = result.slice(0, -1);
  }
  return result;
}

/**
 * 绘制文字块
 *
 * @param maxLines 最大行数，默认无限换行。设为 1 时不换行，超长自动截断。
 */
export function drawTextBlock(
  ctx: CanvasRenderingContext2D,
  text: string,
  centerX: number,
  startY: number,
  style: Partial<AssStyle>,
  scale: number,
  canvasWidth: number,
  maxLines?: number
): number {
  const marginL = (style.marginL ?? 20) * scale;
  const marginR = (style.marginR ?? 20) * scale;
  const maxWidth = canvasWidth - marginL - marginR;
  const fontSize = (style.fontSize ?? 64) * scale * CANVAS_FONT_COMPENSATION;
  const lineHeight = fontSize * 1.2;

  let lines: string[];
  if (maxLines === 1) {
    lines = [truncateText(ctx, text, maxWidth)];
  } else {
    lines = wrapText(ctx, text, maxWidth);
  }

  for (let i = 0; i < lines.length; i++) {
    const y = startY + i * lineHeight;
    drawTextLine(ctx, lines[i], centerX, y, style, scale, canvasWidth);
  }

  return lines.length * lineHeight;
}

/**
 * 加载自定义字体
 *
 * 在 Tauri 桌面应用中，使用资源目录 API 读取字体文件为 base64 data URL，
 * 避免相对路径在自定义协议（tauri://）下失效的问题。
 */
export async function loadCustomFont(): Promise<void> {
  const fontName = 'DouyinSansBold';
  try {
    // 检查字体是否已加载
    if (document.fonts.check(`bold 16px ${fontName}`)) {
      return;
    }

    let fontUrl: string;

    // 方式1: 通过 Tauri API 读取资源目录中的字体文件（生产环境）
    try {
      const bytes = await readFile('fonts/DouyinSansBold.ttf', {
        baseDir: BaseDirectory.Resource,
      });

      // 将 Uint8Array 转为 base64 data URL
      const blob = new Blob([bytes]);
      fontUrl = await new Promise<string>((resolve, reject) => {
        const reader = new FileReader();
        reader.onloadend = () => resolve(reader.result as string);
        reader.onerror = reject;
        reader.readAsDataURL(blob);
      });
    } catch {
      // 方式2: 回退到相对路径（Vite dev server / 浏览器环境）
      fontUrl = '/fonts/DouyinSansBold.ttf';
    }

    const fontFace = new FontFace(fontName, `url(${fontUrl})`, {
      weight: 'bold',
    });
    await fontFace.load();
    document.fonts.add(fontFace);
  } catch {
    // no-op: 字体加载失败已在内部处理
  }
}
