import fs from "node:fs/promises";
import path from "node:path";
import { pool } from "../db/client.js";
import { storageProvider } from "../storage/index.js";
import { annotatePreviewTargets, getPreviewTargetSelector, getPreviewTargetSeeds } from "./previewTargets.js";

type PageWorkspaceSourceRow = {
  project_id: string;
  page_id: string;
  scan_version_id: string;
  source_path: string;
  url_path: string | null;
  title: string | null;
  description: string | null;
  raw: Record<string, unknown>;
  source_type: string;
  source_config: Record<string, unknown>;
};

type DraftRow = {
  id: string;
  project_id: string;
  page_id: string;
  status: string;
  created_at: Date;
  updated_at: Date;
};

type DraftItemRow = {
  id: string;
  draft_id: string;
  field: string;
  original_snapshot_key: string | null;
  working_snapshot_key: string | null;
  working_text: string | null;
  created_at: Date;
  updated_at: Date;
};

type WorkspaceSnapshot = {
  schemaVersion: "page-workspace.v2";
  projectId: string;
  pageId: string;
  scanVersionId: string;
  sourcePath: string;
  urlPath: string | null;
  title: string | null;
  description: string | null;
  headings: Array<{ level: number; text: string }>;
  originalText: string;
  originalHtml: string;
  previewHtml: string;
  sections: PageWorkspaceSection[];
  createdAt: string;
};

export type PageWorkspaceSection = {
  id: string;
  kind: "meta" | "content_block" | "heading_group" | "media";
  title: string;
  selector: string | null;
  originalText: string;
  workingText: string;
  charCount: number;
  summary: string;
  sourceHint: string;
};

export type PageWorkspace = {
  projectId: string;
  pageId: string;
  page: {
    scanVersionId: string;
    sourcePath: string;
    urlPath: string | null;
    title: string | null;
    description: string | null;
    headings: Array<{ level: number; text: string }>;
  };
  draft: {
    id: string;
    status: string;
    createdAt: string;
    updatedAt: string;
  };
  item: {
    id: string;
    field: string;
    originalSnapshotKey: string | null;
    workingSnapshotKey: string | null;
    originalText: string;
    workingText: string;
    originalTextLength: number;
    workingTextLength: number;
    updatedAt: string;
  };
  previewHtml: string;
  sections: PageWorkspaceSection[];
};

export class PageWorkspaceError extends Error {
  constructor(message: string) {
    super(message);
    this.name = "PageWorkspaceError";
  }
}

const WORKSPACE_FIELD = "page_text";
const MAX_BLOCK_TEXT_LENGTH = 6_000;
const MAX_SECTIONS = 80;
const MAX_MEDIA_SECTIONS = 80;

function toIsoDate(value: Date) {
  return value.toISOString();
}

function normalizePath(value: string) {
  return value.replace(/\\/g, "/").replace(/^\/+/, "");
}

function getStringConfig(config: Record<string, unknown>, key: string) {
  const value = config[key];
  return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
}

function decodeHtmlEntities(value: string) {
  return value
    .replace(/&nbsp;/gi, " ")
    .replace(/&amp;/gi, "&")
    .replace(/&quot;/gi, "\"")
    .replace(/&#39;/gi, "'")
    .replace(/&lt;/gi, "<")
    .replace(/&gt;/gi, ">");
}

function normalizeWhitespace(value: string) {
  return decodeHtmlEntities(value).replace(/\s+/g, " ").trim();
}

function stripIgnoredHtmlBlocks(html: string) {
  return html
    .replace(/<script\b[\s\S]*?<\/script>/gi, " ")
    .replace(/<style\b[\s\S]*?<\/style>/gi, " ")
    .replace(/<svg\b[\s\S]*?<\/svg>/gi, " ");
}

function getBodyHtml(html: string) {
  const bodyMatch = /<body\b[^>]*>([\s\S]*?)<\/body>/i.exec(html);
  return bodyMatch?.[1] ?? html;
}

function getAttribute(attributes: string, name: string) {
  const pattern = new RegExp(`${name}\\s*=\\s*["']([^"']*)["']`, "i");
  return pattern.exec(attributes)?.[1] ?? null;
}

function getDisplayFilename(source: string | null, fallback: string) {
  if (!source) {
    return fallback;
  }

  const cleanSource = source.split(/[?#]/)[0] ?? source;
  return path.basename(cleanSource) || source;
}

function htmlToReadableText(html: string) {
  const withBreaks = stripIgnoredHtmlBlocks(html)
    .replace(/<br\s*\/?>/gi, "\n")
    .replace(/<\/(p|div|section|article|header|footer|main|aside|nav|li|ul|ol|h[1-6])>/gi, "\n")
    .replace(/<(h[1-6])\b[^>]*>/gi, "\n");

  return decodeHtmlEntities(withBreaks.replace(/<[^>]+>/g, " "))
    .split(/\n+/)
    .map((line) => normalizeWhitespace(line))
    .filter(Boolean)
    .join("\n")
    .slice(0, MAX_BLOCK_TEXT_LENGTH);
}

function normalizeHeadings(raw: Record<string, unknown>) {
  const headings = raw.headings;

  if (!Array.isArray(headings)) {
    return [];
  }

  return headings
    .map((heading) => {
      if (typeof heading !== "object" || heading === null) {
        return null;
      }

      const level = "level" in heading && typeof heading.level === "number" ? heading.level : null;
      const text = "text" in heading && typeof heading.text === "string" ? heading.text : null;

      return level && text ? { level, text } : null;
    })
    .filter((heading): heading is { level: number; text: string } => Boolean(heading));
}

function getFirstH1Text(raw: Record<string, unknown>) {
  return normalizeHeadings(raw).find((heading) => heading.level === 1)?.text ?? "";
}

function countImageTags(html: string) {
  return Array.from(getBodyHtml(html).matchAll(/<img\b[^>]*>/gi)).length;
}

function getSectionSummary(text: string) {
  const firstMeaningfulLine = text
    .split("\n")
    .map((line) => line.trim())
    .find((line) => line.length > 0);

  if (!firstMeaningfulLine) {
    return "Пустой текстовый блок.";
  }

  return firstMeaningfulLine.length > 180 ? `${firstMeaningfulLine.slice(0, 177)}...` : firstMeaningfulLine;
}

function makeSection(input: Omit<PageWorkspaceSection, "charCount" | "summary" | "workingText">): PageWorkspaceSection {
  return {
    ...input,
    workingText: input.originalText,
    charCount: input.originalText.length,
    summary: getSectionSummary(input.originalText)
  };
}

function getFirstHeadingText(html: string) {
  const headingMatch = /<h([1-6])\b[^>]*>([\s\S]*?)<\/h\1>/i.exec(html);
  return headingMatch ? htmlToReadableText(headingMatch[2] ?? "") : null;
}

function getSemanticBlockTitle(tagName: string, attributes: string, text: string, fallbackIndex: number) {
  const heading = getFirstHeadingText(text);
  const id = getAttribute(attributes, "id");
  const className = getAttribute(attributes, "class");
  const label = getAttribute(attributes, "aria-label");

  if (heading) return heading;
  if (label) return label;
  if (id) return `${tagName}#${id}`;
  if (className) return `${tagName}.${className.split(/\s+/).filter(Boolean).slice(0, 2).join(".")}`;
  return `Блок ${fallbackIndex}`;
}

function dedupeSections(sections: PageWorkspaceSection[]) {
  const seenTexts = new Set<string>();
  const dedupedSections: PageWorkspaceSection[] = [];

  for (const section of sections) {
    const normalizedText = normalizeWhitespace(section.originalText).toLocaleLowerCase();

    if (!normalizedText || seenTexts.has(normalizedText)) {
      continue;
    }

    seenTexts.add(normalizedText);
    dedupedSections.push(section);
  }

  return dedupedSections.slice(0, MAX_SECTIONS);
}

function extractSemanticSections(html: string) {
  const bodyHtml = getBodyHtml(html);
  const blockPattern = /<(section|article|header|main|footer|aside|nav)\b([^>]*)>([\s\S]*?)<\/\1>/gi;
  const sections: PageWorkspaceSection[] = [];
  let match: RegExpExecArray | null;
  let index = 1;

  while ((match = blockPattern.exec(bodyHtml)) && sections.length < MAX_SECTIONS) {
    const tagName = match[1] ?? "section";
    const attributes = match[2] ?? "";
    const blockHtml = match[3] ?? "";
    const text = htmlToReadableText(blockHtml);

    if (text.length < 20) {
      continue;
    }

    sections.push(
      makeSection({
        id: `block-${index}`,
        kind: "content_block",
        title: getSemanticBlockTitle(tagName, attributes, blockHtml, index),
        selector: getPreviewTargetSelector(`block-${index}`),
        originalText: text,
        sourceHint: `<${tagName}>`
      })
    );
    index += 1;
  }

  return dedupeSections(sections);
}

function extractHeadingSections(html: string) {
  const bodyHtml = getBodyHtml(html);
  const headingPattern = /<h([1-6])\b[^>]*>([\s\S]*?)<\/h\1>/gi;
  const headingMatches = Array.from(bodyHtml.matchAll(headingPattern));
  const sections: PageWorkspaceSection[] = [];

  headingMatches.forEach((headingMatch, index) => {
    if (sections.length >= MAX_SECTIONS) {
      return;
    }

    const level = headingMatch[1] ?? "";
    const headingHtml = headingMatch[2] ?? "";
    const startIndex = headingMatch.index ?? 0;
    const nextIndex = headingMatches[index + 1]?.index ?? bodyHtml.length;
    const chunkHtml = bodyHtml.slice(startIndex, nextIndex);
    const text = htmlToReadableText(chunkHtml);
    const headingText = htmlToReadableText(headingHtml) || `H${level}`;

    if (text.length < 8) {
      return;
    }

    sections.push(
      makeSection({
        id: `heading-group-${index + 1}`,
        kind: "heading_group",
        title: `H${level}: ${headingText}`,
        selector: getPreviewTargetSelector(`heading-group-${index + 1}`),
        originalText: text,
        sourceHint: "heading-группа"
      })
    );
  });

  return dedupeSections(sections);
}

function extractImageAltSections(html: string) {
  const bodyHtml = getBodyHtml(html);
  const imagePattern = /<img\b([^>]*)>/gi;
  const sections: PageWorkspaceSection[] = [];
  let match: RegExpExecArray | null;
  let imageIndex = 0;

  while ((match = imagePattern.exec(bodyHtml)) && sections.length < MAX_MEDIA_SECTIONS) {
    imageIndex += 1;

    const attributes = match[1] ?? "";
    const source = getAttribute(attributes, "src");
    const alt = getAttribute(attributes, "alt");
    const normalizedAlt = normalizeWhitespace(alt ?? "");

    const filename = getDisplayFilename(source, `image-${imageIndex}`);

    sections.push(
      makeSection({
        id: `media-alt-${imageIndex}`,
        kind: "media",
        title: `ALT: ${filename}`,
        selector: getPreviewTargetSelector(`media-alt-${imageIndex}`),
        originalText: normalizedAlt,
        sourceHint: source ?? `img:nth-of-type(${imageIndex})`
      })
    );
  }

  return sections;
}

function buildPreviewHtml(html: string) {
  const previewStyles = `
    <style>
      html { background: #fff !important; }
      body { min-height: 100vh; }
      a { cursor: default !important; }
    </style>
  `;
  let imageIndex = 0;
  const targetSeeds = getPreviewTargetSeeds(html);
  const withoutScripts = annotatePreviewTargets(html, targetSeeds)
    .replace(/<script\b[\s\S]*?<\/script>/gi, "")
    .replace(/\son[a-z]+\s*=\s*["'][^"']*["']/gi, "")
    .replace(/<h([1-3])\b([^>]*)>/gi, (_match, level: string, attributes: string) => {
      return `<h${level}${attributes} data-seo-label="H${level}">`;
    })
    .replace(/<img\b([^>]*)>/gi, (match, attributes: string) => {
      imageIndex += 1;

      if (/data-seo-media-index\s*=/i.test(attributes)) {
        return match;
      }

      const isSelfClosing = /\/\s*$/.test(attributes);
      const cleanAttributes = attributes.replace(/\/\s*$/, "").trimEnd();
      return `<img${cleanAttributes} data-seo-media-index="${imageIndex}"${isSelfClosing ? " /" : ""}>`;
    });

  if (/<head\b[^>]*>/i.test(withoutScripts)) {
    return withoutScripts.replace(/<head\b[^>]*>/i, (headTag) => `${headTag}<base target="_blank">${previewStyles}`);
  }

  return `<!doctype html><html><head><base target="_blank">${previewStyles}</head><body>${withoutScripts}</body></html>`;
}

function buildSections(page: PageWorkspaceSourceRow, html: string): PageWorkspaceSection[] {
  const sections: PageWorkspaceSection[] = [];

  if (page.title) {
    sections.push(makeSection({
      id: "seo-title",
      kind: "meta",
      title: "Title",
      selector: "head > title",
      originalText: page.title,
      sourceHint: "SEO-поле"
    }));
  }

  if (page.description) {
    sections.push(makeSection({
      id: "seo-description",
      kind: "meta",
      title: "Meta description",
      selector: "meta[name='description']",
      originalText: page.description,
      sourceHint: "SEO-поле"
    }));
  }

  const semanticSections = extractSemanticSections(html);
  const contentSections = semanticSections.length >= 2 ? semanticSections : extractHeadingSections(html);
  const mediaSections = extractImageAltSections(html);

  return [...sections, ...contentSections, ...mediaSections];
}

function buildIssueAlignedSections(page: PageWorkspaceSourceRow, html: string): PageWorkspaceSection[] {
  const semanticSections = extractSemanticSections(html);
  const contentSections = semanticSections.length >= 2 ? semanticSections : extractHeadingSections(html);
  const mediaSections = extractImageAltSections(html);
  const pageAnchorSelector = contentSections[0]?.selector ?? mediaSections[0]?.selector ?? getPreviewTargetSelector("block-1");
  const h1Section = contentSections.find((section) => section.title.toLocaleLowerCase().startsWith("h1:"));
  const seoSections: PageWorkspaceSection[] = [
    makeSection({
      id: "seo-title",
      kind: "meta",
      title: "Title",
      selector: pageAnchorSelector,
      originalText: page.title ?? "",
      sourceHint: "<title>"
    }),
    makeSection({
      id: "seo-description",
      kind: "meta",
      title: "Meta description",
      selector: pageAnchorSelector,
      originalText: page.description ?? "",
      sourceHint: "meta[name='description']"
    }),
    makeSection({
      id: "seo-h1",
      kind: "heading_group",
      title: "H1",
      selector: h1Section?.selector ?? pageAnchorSelector,
      originalText: getFirstH1Text(page.raw),
      sourceHint: "H1"
    })
  ];

  return [...seoSections, ...contentSections, ...mediaSections];
}

function buildOriginalText(page: PageWorkspaceSourceRow, sections: PageWorkspaceSection[]) {
  const header = [
    `Источник: ${page.source_path}`,
    page.url_path ? `URL: ${page.url_path}` : null,
    `Scan version: ${page.scan_version_id}`
  ].filter(Boolean);

  const sectionText = sections.map((section) => {
    return `## ${section.title}\n${section.originalText}`;
  });

  return [...header, "", ...sectionText].join("\n\n").trim();
}

function extractWorkingSectionTexts(workingText: string, sectionCount: number) {
  const headings = Array.from(workingText.matchAll(/^## .+$/gm));

  if (headings.length === 0) {
    return [];
  }

  return headings.slice(0, sectionCount).map((heading, index) => {
    const start = (heading.index ?? 0) + heading[0].length;
    const end = headings[index + 1]?.index ?? workingText.length;
    return workingText.slice(start, end).trim();
  });
}

async function getLatestPageWorkspaceSource(projectId: string, pageId: string) {
  const result = await pool.query<PageWorkspaceSourceRow>(
    `
      select
        sv.project_id,
        pv.page_id,
        pv.scan_version_id,
        pv.source_path,
        pv.url_path,
        pv.title,
        pv.description,
        pv.raw,
        ps.type as source_type,
        ps.config as source_config
      from page_versions pv
      join scan_versions sv on sv.id = pv.scan_version_id
      join project_sources ps on ps.id = sv.source_id
      where sv.project_id = $1
        and pv.page_id = $2
        and sv.status = 'done'
      order by sv.completed_at desc nulls last, sv.created_at desc
      limit 1;
    `,
    [projectId, pageId]
  );

  return result.rows[0] ?? null;
}

async function readPageHtml(page: PageWorkspaceSourceRow) {
  if (page.source_type === "browser_folder") {
    const importPrefix = getStringConfig(page.source_config, "importPrefix");

    if (!importPrefix) {
      throw new PageWorkspaceError("У проекта нет importPrefix для чтения HTML из MinIO.");
    }

    const normalizedPrefix = importPrefix.endsWith("/") ? importPrefix : `${importPrefix}/`;
    return storageProvider.getObjectText(`${normalizedPrefix}${normalizePath(page.source_path)}`);
  }

  if (page.source_type === "local_folder") {
    const sourcePath = getStringConfig(page.source_config, "path");

    if (!sourcePath) {
      throw new PageWorkspaceError("У проекта нет локального пути для чтения HTML.");
    }

    return fs.readFile(path.join(sourcePath, normalizePath(page.source_path)), "utf8");
  }

  throw new PageWorkspaceError("Рабочая зона для этого типа источника пока не поддерживается.");
}

async function getActiveDraft(projectId: string, pageId: string) {
  const result = await pool.query<DraftRow>(
    `
      select *
      from drafts
      where project_id = $1 and page_id = $2 and status = 'active'
      order by updated_at desc
      limit 1;
    `,
    [projectId, pageId]
  );

  return result.rows[0] ?? null;
}

async function getDraftItem(draftId: string) {
  const result = await pool.query<DraftItemRow>(
    `
      select *
      from draft_items
      where draft_id = $1 and field = $2
      order by updated_at desc
      limit 1;
    `,
    [draftId, WORKSPACE_FIELD]
  );

  return result.rows[0] ?? null;
}

async function readOriginalSnapshot(key: string | null) {
  if (!key) {
    throw new PageWorkspaceError("У draft нет original snapshot.");
  }

  const text = await storageProvider.getObjectText(key);
  return JSON.parse(text) as WorkspaceSnapshot;
}

function buildWorkspaceResponse(page: PageWorkspaceSourceRow, draft: DraftRow, item: DraftItemRow, snapshot: WorkspaceSnapshot): PageWorkspace {
  const workingText = item.working_text ?? snapshot.originalText;
  const workingSectionTexts = extractWorkingSectionTexts(workingText, snapshot.sections.length);
  const sections = snapshot.sections.map((section, index) => {
    const sectionWorkingText = workingSectionTexts[index] ?? section.originalText;

    return {
      ...section,
      workingText: sectionWorkingText,
      charCount: sectionWorkingText.length,
      summary: getSectionSummary(sectionWorkingText)
    };
  });

  return {
    projectId: page.project_id,
    pageId: page.page_id,
    page: {
      scanVersionId: page.scan_version_id,
      sourcePath: page.source_path,
      urlPath: page.url_path,
      title: page.title,
      description: page.description,
      headings: normalizeHeadings(page.raw)
    },
    draft: {
      id: draft.id,
      status: draft.status,
      createdAt: toIsoDate(draft.created_at),
      updatedAt: toIsoDate(draft.updated_at)
    },
    item: {
      id: item.id,
      field: item.field,
      originalSnapshotKey: item.original_snapshot_key,
      workingSnapshotKey: item.working_snapshot_key,
      originalText: snapshot.originalText,
      workingText,
      originalTextLength: snapshot.originalText.length,
      workingTextLength: workingText.length,
      updatedAt: toIsoDate(item.updated_at)
    },
    previewHtml: snapshot.previewHtml,
    sections
  };
}

function buildSnapshot(page: PageWorkspaceSourceRow, html: string): WorkspaceSnapshot {
  const sections = buildIssueAlignedSections(page, html);
  const originalText = buildOriginalText(page, sections);

  return {
    schemaVersion: "page-workspace.v2",
    projectId: page.project_id,
    pageId: page.page_id,
    scanVersionId: page.scan_version_id,
    sourcePath: page.source_path,
    urlPath: page.url_path,
    title: page.title,
    description: page.description,
    headings: normalizeHeadings(page.raw),
    originalText,
    originalHtml: html,
    previewHtml: buildPreviewHtml(html),
    sections,
    createdAt: new Date().toISOString()
  };
}

async function getUpgradedSnapshot(page: PageWorkspaceSourceRow, item: DraftItemRow) {
  const snapshot = await readOriginalSnapshot(item.original_snapshot_key);
  const imageCount = Math.min(countImageTags(snapshot.originalHtml ?? ""), MAX_MEDIA_SECTIONS);
  const mediaSectionCount = snapshot.sections.filter((section) => section.kind === "media").length;
  const isCurrentSnapshot =
    snapshot.schemaVersion === "page-workspace.v2" &&
    "previewHtml" in snapshot &&
    snapshot.sections.some((section) => section.id === "seo-title") &&
    snapshot.sections.some((section) => section.id === "seo-description") &&
    snapshot.sections.some((section) => section.id === "seo-h1") &&
    snapshot.sections.some((section) => section.kind === "content_block" || section.kind === "heading_group") &&
    (!/<img\b/i.test(snapshot.originalHtml ?? "") || mediaSectionCount >= imageCount) &&
    snapshot.sections.every((section) => section.kind === "meta" || section.selector?.includes("data-seo-target-id"));

  if (isCurrentSnapshot) {
    return snapshot;
  }

  const html = snapshot.originalHtml || (await readPageHtml(page));
  const upgradedSnapshot = buildSnapshot(page, html);

  if (item.original_snapshot_key) {
    await storageProvider.putObject({
      key: item.original_snapshot_key,
      body: JSON.stringify(upgradedSnapshot, null, 2),
      contentType: "application/json"
    });
  }

  if (!item.working_text || item.working_text === snapshot.originalText) {
    await pool.query(
      `
        update draft_items
        set working_text = $1, updated_at = now()
        where id = $2;
      `,
      [upgradedSnapshot.originalText, item.id]
    );
    item.working_text = upgradedSnapshot.originalText;
    item.updated_at = new Date();
  }

  return upgradedSnapshot;
}

export async function getOrCreatePageWorkspace(projectId: string, pageId: string) {
  const page = await getLatestPageWorkspaceSource(projectId, pageId);

  if (!page) {
    return null;
  }

  const existingDraft = await getActiveDraft(projectId, pageId);
  const existingItem = existingDraft ? await getDraftItem(existingDraft.id) : null;

  if (existingDraft && existingItem) {
    const snapshot = await getUpgradedSnapshot(page, existingItem);
    return buildWorkspaceResponse(page, existingDraft, existingItem, snapshot);
  }

  const html = await readPageHtml(page);
  const snapshot = buildSnapshot(page, html);
  const client = await pool.connect();

  try {
    await client.query("begin");

    const draftResult = await client.query<DraftRow>(
      `
        insert into drafts (project_id, page_id, status)
        values ($1, $2, 'active')
        returning *;
      `,
      [projectId, pageId]
    );
    const draft = draftResult.rows[0];

    if (!draft) {
      throw new Error("Не удалось создать draft.");
    }

    const originalSnapshotKey = `projects/${projectId}/drafts/${draft.id}/original-page-workspace.json`;
    await storageProvider.putObject({
      key: originalSnapshotKey,
      body: JSON.stringify(snapshot, null, 2),
      contentType: "application/json"
    });

    const itemResult = await client.query<DraftItemRow>(
      `
        insert into draft_items (draft_id, field, original_snapshot_key, working_text)
        values ($1, $2, $3, $4)
        returning *;
      `,
      [draft.id, WORKSPACE_FIELD, originalSnapshotKey, snapshot.originalText]
    );
    const item = itemResult.rows[0];

    if (!item) {
      throw new Error("Не удалось создать draft item.");
    }

    await client.query("commit");
    return buildWorkspaceResponse(page, draft, item, snapshot);
  } catch (error) {
    await client.query("rollback");
    throw error;
  } finally {
    client.release();
  }
}

async function updateWorkspaceText(projectId: string, pageId: string, workingText: string) {
  const workspace = await getOrCreatePageWorkspace(projectId, pageId);

  if (!workspace) {
    return null;
  }

  const workingSnapshotKey = `projects/${projectId}/drafts/${workspace.draft.id}/working-${Date.now()}.txt`;

  await storageProvider.putObject({
    key: workingSnapshotKey,
    body: workingText,
    contentType: "text/plain; charset=utf-8"
  });

  await pool.query(
    `
      update draft_items
      set working_text = $1, working_snapshot_key = $2, updated_at = now()
      where id = $3;
    `,
    [workingText, workingSnapshotKey, workspace.item.id]
  );

  await pool.query(
    `
      update drafts
      set updated_at = now()
      where id = $1;
    `,
    [workspace.draft.id]
  );

  return getOrCreatePageWorkspace(projectId, pageId);
}

export async function savePageWorkspace(projectId: string, pageId: string, workingText: string) {
  return updateWorkspaceText(projectId, pageId, workingText);
}

export async function resetPageWorkspace(projectId: string, pageId: string) {
  const workspace = await getOrCreatePageWorkspace(projectId, pageId);

  if (!workspace) {
    return null;
  }

  return updateWorkspaceText(projectId, pageId, workspace.item.originalText);
}
