"use server";

import { drizzle } from "drizzle-orm/node-postgres";
import { redirect } from "next/navigation";
import { v7 } from "uuid";
import { sql } from "drizzle-orm";
import { generateKeyBetween } from "fractional-indexing";
import { cookies } from "next/headers";
import { pool } from "supabase/pool";

type DefaultBlockType = "h1" | "text" | "posts-list";

type FactRow = {
  id: string;
  entity: string;
  attribute: string;
  data: unknown;
};

export async function createNewLeaflet({
  pageType,
  redirectUser,
  firstBlockType,
  welcomeModal,
  addToHome,
  firstBlocks,
  addToHomepage = true,
}: {
  pageType: "canvas" | "doc";
  redirectUser: boolean;
  firstBlockType?: "h1" | "text";
  welcomeModal?: boolean;
  addToHome?: boolean;
  firstBlocks?: DefaultBlockType[];
  addToHomepage?: boolean;
}) {
  let auth_token = (await cookies()).get("auth_token")?.value;

  // Pre-generate every UUID so all inserts can run in one round trip with no
  // RETURNING-driven data dependencies between statements.
  const entitySetId = v7();
  const permTokenId = v7();
  const rootEntityId = v7();
  const firstPageId = v7();

  const factRows: FactRow[] = [
    {
      id: v7(),
      entity: rootEntityId,
      attribute: "root/page",
      data: { type: "ordered-reference", value: firstPageId, position: "a0" },
    },
    {
      id: v7(),
      entity: rootEntityId,
      attribute: "theme/page-leaflet-watermark",
      data: { type: "boolean", value: true },
    },
  ];

  let blockEntityIds: string[];
  if (pageType === "canvas") {
    const blockId = v7();
    blockEntityIds = [blockId];
    factRows.push(
      {
        id: v7(),
        entity: firstPageId,
        attribute: "page/type",
        data: { type: "page-type-union", value: "canvas" },
      },
      {
        id: v7(),
        entity: firstPageId,
        attribute: "canvas/block",
        data: {
          type: "spatial-reference",
          value: blockId,
          position: { x: 8, y: 12 },
        },
      },
      {
        id: v7(),
        entity: blockId,
        attribute: "block/type",
        data: { type: "block-type-union", value: "text" },
      },
    );
  } else {
    const blockSpecs: DefaultBlockType[] =
      firstBlocks ?? [firstBlockType === "text" ? "text" : "h1"];
    blockEntityIds = blockSpecs.map(() => v7());
    let prevPosition: string | null = null;
    blockSpecs.forEach((spec, i) => {
      const entity = blockEntityIds[i];
      const position = generateKeyBetween(prevPosition, null);
      prevPosition = position;
      factRows.push({
        id: v7(),
        entity: firstPageId,
        attribute: "card/block",
        data: { type: "ordered-reference", value: entity, position },
      });
      if (spec === "h1") {
        factRows.push(
          {
            id: v7(),
            entity,
            attribute: "block/type",
            data: { type: "block-type-union", value: "heading" },
          },
          {
            id: v7(),
            entity,
            attribute: "block/heading-level",
            data: { type: "number", value: 1 },
          },
        );
      } else {
        factRows.push({
          id: v7(),
          entity,
          attribute: "block/type",
          data: { type: "block-type-union", value: spec },
        });
      }
    });
  }

  const entityIds = [rootEntityId, firstPageId, ...blockEntityIds];

  const entityValues = sql.join(
    entityIds.map((id) => sql`(${id}, ${entitySetId})`),
    sql`, `,
  );
  const factValues = sql.join(
    factRows.map(
      (f) =>
        sql`(${f.id}, ${f.entity}, ${f.attribute}, ${JSON.stringify(f.data)}::jsonb)`,
    ),
    sql`, `,
  );

  // Optional homepage insert as a tail CTE; resolves auth_token → identity in
  // the same round trip and inserts nothing when the token is missing/invalid.
  const homepageCte =
    auth_token && addToHomepage
      ? sql`, homepage_insert AS (
          INSERT INTO permission_token_on_homepage (token, identity)
          SELECT ${permTokenId}, identities.id
          FROM email_auth_tokens
          JOIN identities ON email_auth_tokens.identity = identities.id
          WHERE email_auth_tokens.id = ${auth_token}
            AND email_auth_tokens.confirmed = true
        )`
      : sql``;

  // All inserts in a single statement. FK checks fire at end-of-statement and
  // see rows inserted in sibling data-modifying CTEs, so ordering is safe.
  // Atomicity comes from the statement itself — no explicit transaction needed.
  const client = await pool.connect();
  const db = drizzle(client);
  try {
    await db.execute(sql`
      WITH new_set AS (
        INSERT INTO entity_sets (id) VALUES (${entitySetId})
      ),
      new_entities AS (
        INSERT INTO entities (id, set) VALUES ${entityValues}
      ),
      new_token AS (
        INSERT INTO permission_tokens (id, root_entity)
        VALUES (${permTokenId}, ${rootEntityId})
      ),
      new_rights AS (
        INSERT INTO permission_token_rights
          (token, entity_set, read, write, create_token, change_entity_set)
        VALUES (${permTokenId}, ${entitySetId}, true, true, true, true)
      ),
      new_facts AS (
        INSERT INTO facts (id, entity, attribute, data) VALUES ${factValues}
      )${homepageCte}
      SELECT 1
    `);
  } finally {
    client.release();
  }

  if (redirectUser)
    redirect(
      `/${permTokenId}?focusFirstBlock${welcomeModal ? "&welcomeModal" : ""}${addToHome ? "&addToHome" : ""}`,
    );
  return permTokenId;
}
