import { z } from "zod";
import { THREADS_MAX_CHARS } from "@/lib/utils";
import type { MatrixRow } from "@/lib/types/research";
import { explainProviderApiError } from "./opencode-go-settings";

export const matrixLooseSchema = z.object({
  rows: z
    .array(
      z.object({
        sortOrder: z.union([z.number(), z.string()]).optional(),
        searchTag: z.string().optional(),
        angle: z.string().optional(),
        hook: z.string().optional(),
        text: z.string().optional(),
        referenceNotes: z.string().optional(),
        sourcePermalinks: z.union([z.array(z.string()), z.string()]).optional(),
        rationale: z.string().optional(),
      })
    )
    .min(1),
});

function asString(value: unknown): string {
  if (typeof value === "string") return value.trim();
  if (typeof value === "number" || typeof value === "boolean") return String(value);
  return "";
}

function asStringArray(value: unknown): string[] {
  if (Array.isArray(value)) {
    return value.map((item) => asString(item)).filter(Boolean);
  }
  const single = asString(value);
  return single ? [single] : [];
}

function asSortOrder(value: unknown, fallback: number): number {
  if (typeof value === "number" && Number.isFinite(value)) return Math.max(1, Math.floor(value));
  const parsed = parseInt(asString(value), 10);
  return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
}

export function coerceMatrixRaw(
  parsed: unknown,
  fallback: { query: string; count: number }
): MatrixRow[] {
  const root =
    parsed && typeof parsed === "object" ? (parsed as Record<string, unknown>) : {};

  const rowsRaw =
    root.rows ??
    root.matrix ??
    root.content ??
    (Array.isArray(parsed) ? parsed : null);

  if (!Array.isArray(rowsRaw) || rowsRaw.length === 0) {
    throw new Error("AI 回傳的內容矩陣缺少 rows 陣列");
  }

  const rows: MatrixRow[] = [];
  for (let i = 0; i < rowsRaw.length; i++) {
    const item = rowsRaw[i];
    if (!item || typeof item !== "object") continue;
    const obj = item as Record<string, unknown>;

    const text = asString(obj.text ?? obj.body ?? obj.post ?? obj.content);
    if (!text) continue;

    rows.push({
      sortOrder: asSortOrder(obj.sortOrder ?? obj.order ?? obj.index, i + 1),
      searchTag: asString(obj.searchTag ?? obj.tag ?? obj.topic) || fallback.query,
      angle: asString(obj.angle ?? obj.perspective) || "待補切角",
      hook: asString(obj.hook ?? obj.opening) || text.split("\n")[0]?.slice(0, 80) || text.slice(0, 80),
      text: text.slice(0, THREADS_MAX_CHARS),
      referenceNotes:
        asString(obj.referenceNotes ?? obj.references ?? obj.notes) || "（待補參考重點）",
      sourcePermalinks: asStringArray(obj.sourcePermalinks ?? obj.sources ?? obj.permalinks),
      rationale: asString(obj.rationale ?? obj.reason) || "依優質素材衍生的企劃切角",
    });
  }

  if (rows.length === 0) {
    throw new Error("AI 回傳的內容矩陣沒有可用貼文");
  }

  return rows
    .sort((a, b) => a.sortOrder - b.sortOrder)
    .map((row, index) => ({ ...row, sortOrder: index + 1 }))
    .slice(0, fallback.count);
}

export function formatMatrixError(error: unknown): string {
  if (typeof error === "string") return error;
  if (error instanceof z.ZodError) {
    const detail = error.issues
      .slice(0, 3)
      .map((issue) => `${issue.path.join(".") || "回傳內容"}：${issue.message}`)
      .join("；");
    return `AI 回傳的內容矩陣格式不完整（${detail}）。請再試一次。`;
  }
  if (error instanceof Error) {
    const extra = error as Error & { responseBody?: string };
    const body = typeof extra.responseBody === "string" ? extra.responseBody : "";
    const explained = explainProviderApiError(error.message, body);
    if (explained) return explained;
    if (body.includes("hex escape") || body.includes("parse the request body")) {
      return "參考素材含有特殊字元，導致 AI 請求格式錯誤。系統已自動清理字元，請再按一次「內容矩陣」。";
    }
    if (error.message === "Bad Request" && body) {
      return `AI 請求失敗：${body.slice(0, 200)}`;
    }
    if (error.message === "Bad Request") {
      return "AI 供應商拒絕請求（Bad Request）。請到設定頁確認 API key 或更換模型後重試。";
    }
    return error.message;
  }
  return "生成內容矩陣失敗";
}