import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-postgres';

/**
 * Migration: native_localization
 *
 * Transforms the existing schema (manual `locale` select column on each row)
 * into Payload's native localization join-table structure.
 *
 * Each statement is a separate db.execute call to avoid Drizzle multi-statement issues.
 */
export async function up({ db }: MigrateUpArgs): Promise<void> {
  // ── 1. Global locale enum ────────────────────────────────────────────────────
  await db.execute(sql`
    DO $$ BEGIN
      CREATE TYPE "public"."enum__locales" AS ENUM('de', 'en');
    EXCEPTION WHEN duplicate_object THEN null; END $$
  `);
  await db.execute(sql`
    DO $$ BEGIN
      CREATE TYPE "public"."enum__posts_v_published_locale" AS ENUM('de', 'en');
    EXCEPTION WHEN duplicate_object THEN null; END $$
  `);
  await db.execute(sql`
    DO $$ BEGIN
      CREATE TYPE "public"."enum__products_v_published_locale" AS ENUM('de', 'en');
    EXCEPTION WHEN duplicate_object THEN null; END $$
  `);
  await db.execute(sql`
    DO $$ BEGIN
      CREATE TYPE "public"."enum__pages_v_published_locale" AS ENUM('de', 'en');
    EXCEPTION WHEN duplicate_object THEN null; END $$
  `);
  await db.execute(sql`
    DO $$ BEGIN
      CREATE TYPE "public"."enum_pages_layout" AS ENUM('default', 'fullBleed');
    EXCEPTION WHEN duplicate_object THEN null; END $$
  `);
  await db.execute(sql`
    DO $$ BEGIN
      CREATE TYPE "public"."enum__pages_v_version_layout" AS ENUM('default', 'fullBleed');
    EXCEPTION WHEN duplicate_object THEN null; END $$
  `);
  await db.execute(sql`
    DO $$ BEGIN
      CREATE TYPE "public"."enum__pages_v_version_status" AS ENUM('draft', 'published');
    EXCEPTION WHEN duplicate_object THEN null; END $$
  `);
  await db.execute(sql`
    DO $$ BEGIN
      CREATE TYPE "public"."enum__posts_v_version_status" AS ENUM('draft', 'published');
    EXCEPTION WHEN duplicate_object THEN null; END $$
  `);
  await db.execute(sql`
    DO $$ BEGIN
      CREATE TYPE "public"."enum__products_v_version_status" AS ENUM('draft', 'published');
    EXCEPTION WHEN duplicate_object THEN null; END $$
  `);

  // ── 2. Alter pages table ─────────────────────────────────────────────────────
  await db.execute(sql`ALTER TABLE "pages" ADD COLUMN IF NOT EXISTS "layout" "enum_pages_layout" DEFAULT 'default'`);
  await db.execute(sql`ALTER TABLE "pages" ADD COLUMN IF NOT EXISTS "_status" "enum_pages_status" DEFAULT 'draft'`);

  // ── 3. Create pages_locales join table ───────────────────────────────────────
  await db.execute(sql`
    CREATE TABLE IF NOT EXISTS "pages_locales" (
      "title" varchar,
      "slug" varchar,
      "excerpt" varchar,
      "content" jsonb,
      "id" serial PRIMARY KEY NOT NULL,
      "_locale" "enum__locales" NOT NULL,
      "_parent_id" integer NOT NULL
    )
  `);
  await db.execute(sql`
    DO $$ BEGIN
      ALTER TABLE "pages_locales" ADD CONSTRAINT "pages_locales_locale_parent_id_unique" UNIQUE("_locale", "_parent_id");
    EXCEPTION WHEN duplicate_object THEN null; END $$
  `);
  await db.execute(sql`
    DO $$ BEGIN
      ALTER TABLE "pages_locales" ADD CONSTRAINT "pages_locales_parent_id_fk"
        FOREIGN KEY ("_parent_id") REFERENCES "pages"("id") ON DELETE cascade;
    EXCEPTION WHEN duplicate_object THEN null; END $$
  `);

  // ── 4. Backfill pages_locales from old pages rows ────────────────────────────
  await db.execute(sql`
    INSERT INTO "pages_locales" ("title", "slug", "excerpt", "content", "_locale", "_parent_id")
    SELECT
      p.title, p.slug, p.excerpt, p.content,
      CASE WHEN p.locale::text = 'de' THEN 'de'::"enum__locales" ELSE 'en'::"enum__locales" END,
      p.id
    FROM "pages" p
    WHERE p.locale IS NOT NULL
    ON CONFLICT ("_locale", "_parent_id") DO UPDATE
      SET "title" = EXCLUDED."title",
          "slug" = EXCLUDED."slug",
          "excerpt" = EXCLUDED."excerpt",
          "content" = EXCLUDED."content"
  `);

  // ── 5. Drop old columns from pages ───────────────────────────────────────────
  await db.execute(sql`ALTER TABLE "pages" DROP COLUMN IF EXISTS "title"`);
  await db.execute(sql`ALTER TABLE "pages" DROP COLUMN IF EXISTS "slug"`);
  await db.execute(sql`ALTER TABLE "pages" DROP COLUMN IF EXISTS "excerpt"`);
  await db.execute(sql`ALTER TABLE "pages" DROP COLUMN IF EXISTS "content"`);
  await db.execute(sql`ALTER TABLE "pages" DROP COLUMN IF EXISTS "locale"`);

  // ── 6. Create posts_locales join table ───────────────────────────────────────
  await db.execute(sql`
    CREATE TABLE IF NOT EXISTS "posts_locales" (
      "title" varchar,
      "slug" varchar,
      "excerpt" varchar,
      "category" varchar,
      "content" jsonb,
      "id" serial PRIMARY KEY NOT NULL,
      "_locale" "enum__locales" NOT NULL,
      "_parent_id" integer NOT NULL
    )
  `);
  await db.execute(sql`
    DO $$ BEGIN
      ALTER TABLE "posts_locales" ADD CONSTRAINT "posts_locales_locale_parent_id_unique" UNIQUE("_locale", "_parent_id");
    EXCEPTION WHEN duplicate_object THEN null; END $$
  `);
  await db.execute(sql`
    DO $$ BEGIN
      ALTER TABLE "posts_locales" ADD CONSTRAINT "posts_locales_parent_id_fk"
        FOREIGN KEY ("_parent_id") REFERENCES "posts"("id") ON DELETE cascade;
    EXCEPTION WHEN duplicate_object THEN null; END $$
  `);

  // ── 7. Backfill posts_locales ────────────────────────────────────────────────
  await db.execute(sql`
    INSERT INTO "posts_locales" ("title", "slug", "excerpt", "category", "content", "_locale", "_parent_id")
    SELECT
      p.title, p.slug, p.excerpt, p.category, p.content,
      CASE WHEN p.locale::text = 'de' THEN 'de'::"enum__locales" ELSE 'en'::"enum__locales" END,
      p.id
    FROM "posts" p
    WHERE p.locale IS NOT NULL
    ON CONFLICT ("_locale", "_parent_id") DO UPDATE
      SET "title" = EXCLUDED."title",
          "slug" = EXCLUDED."slug",
          "excerpt" = EXCLUDED."excerpt",
          "category" = EXCLUDED."category",
          "content" = EXCLUDED."content"
  `);

  // ── 8. Drop old columns from posts ───────────────────────────────────────────
  await db.execute(sql`ALTER TABLE "posts" DROP COLUMN IF EXISTS "title"`);
  await db.execute(sql`ALTER TABLE "posts" DROP COLUMN IF EXISTS "slug"`);
  await db.execute(sql`ALTER TABLE "posts" DROP COLUMN IF EXISTS "excerpt"`);
  await db.execute(sql`ALTER TABLE "posts" DROP COLUMN IF EXISTS "category"`);
  await db.execute(sql`ALTER TABLE "posts" DROP COLUMN IF EXISTS "content"`);
  await db.execute(sql`ALTER TABLE "posts" DROP COLUMN IF EXISTS "locale"`);

  // ── 9. Create products_locales join table ────────────────────────────────────
  await db.execute(sql`
    CREATE TABLE IF NOT EXISTS "products_locales" (
      "title" varchar,
      "description" varchar,
      "application" jsonb,
      "content" jsonb,
      "id" serial PRIMARY KEY NOT NULL,
      "_locale" "enum__locales" NOT NULL,
      "_parent_id" integer NOT NULL
    )
  `);
  await db.execute(sql`
    DO $$ BEGIN
      ALTER TABLE "products_locales" ADD CONSTRAINT "products_locales_locale_parent_id_unique" UNIQUE("_locale", "_parent_id");
    EXCEPTION WHEN duplicate_object THEN null; END $$
  `);
  await db.execute(sql`
    DO $$ BEGIN
      ALTER TABLE "products_locales" ADD CONSTRAINT "products_locales_parent_id_fk"
        FOREIGN KEY ("_parent_id") REFERENCES "products"("id") ON DELETE cascade;
    EXCEPTION WHEN duplicate_object THEN null; END $$
  `);

  // ── 10. Backfill products_locales ────────────────────────────────────────────
  // Products were separate DE/EN rows — each becomes a locale entry on its own id
  await db.execute(sql`
    INSERT INTO "products_locales" ("title", "description", "application", "content", "_locale", "_parent_id")
    SELECT
      p.title, p.description, p.application, p.content,
      CASE WHEN p.locale::text = 'de' THEN 'de'::"enum__locales" ELSE 'en'::"enum__locales" END,
      p.id
    FROM "products" p
    WHERE p.locale IS NOT NULL
    ON CONFLICT ("_locale", "_parent_id") DO NOTHING
  `);

  // ── 11. Drop old columns from products ───────────────────────────────────────
  await db.execute(sql`ALTER TABLE "products" DROP COLUMN IF EXISTS "title"`);
  await db.execute(sql`ALTER TABLE "products" DROP COLUMN IF EXISTS "description"`);
  await db.execute(sql`ALTER TABLE "products" DROP COLUMN IF EXISTS "application"`);
  await db.execute(sql`ALTER TABLE "products" DROP COLUMN IF EXISTS "content"`);
  await db.execute(sql`ALTER TABLE "products" DROP COLUMN IF EXISTS "locale"`);

  // ── 12. Version tables (_posts_v, _products_v, _pages_v) locale columns ──────
  await db.execute(sql`ALTER TABLE "_posts_v" ADD COLUMN IF NOT EXISTS "published_locale" "enum__posts_v_published_locale"`);
  await db.execute(sql`ALTER TABLE "_products_v" ADD COLUMN IF NOT EXISTS "published_locale" "enum__products_v_published_locale"`);
  await db.execute(sql`ALTER TABLE "_pages_v" ADD COLUMN IF NOT EXISTS "published_locale" "enum__pages_v_published_locale"`);

  // ── 13. Create _posts_v_locales ──────────────────────────────────────────────
  await db.execute(sql`
    CREATE TABLE IF NOT EXISTS "_posts_v_locales" (
      "version_title" varchar, "version_slug" varchar, "version_excerpt" varchar,
      "version_category" varchar, "version_content" jsonb,
      "id" serial PRIMARY KEY NOT NULL,
      "_locale" "enum__locales" NOT NULL, "_parent_id" integer NOT NULL
    )
  `);
  await db.execute(sql`
    DO $$ BEGIN
      ALTER TABLE "_posts_v_locales" ADD CONSTRAINT "_posts_v_locales_locale_parent_id_unique" UNIQUE("_locale", "_parent_id");
    EXCEPTION WHEN duplicate_object THEN null; END $$
  `);
  await db.execute(sql`
    DO $$ BEGIN
      ALTER TABLE "_posts_v_locales" ADD CONSTRAINT "_posts_v_locales_parent_id_fk"
        FOREIGN KEY ("_parent_id") REFERENCES "_posts_v"("id") ON DELETE cascade;
    EXCEPTION WHEN duplicate_object THEN null; END $$
  `);

  // ── 14. Create _products_v_locales ───────────────────────────────────────────
  await db.execute(sql`
    CREATE TABLE IF NOT EXISTS "_products_v_locales" (
      "version_title" varchar, "version_description" varchar,
      "version_application" jsonb, "version_content" jsonb,
      "id" serial PRIMARY KEY NOT NULL,
      "_locale" "enum__locales" NOT NULL, "_parent_id" integer NOT NULL
    )
  `);
  await db.execute(sql`
    DO $$ BEGIN
      ALTER TABLE "_products_v_locales" ADD CONSTRAINT "_products_v_locales_locale_parent_id_unique" UNIQUE("_locale", "_parent_id");
    EXCEPTION WHEN duplicate_object THEN null; END $$
  `);
  await db.execute(sql`
    DO $$ BEGIN
      ALTER TABLE "_products_v_locales" ADD CONSTRAINT "_products_v_locales_parent_id_fk"
        FOREIGN KEY ("_parent_id") REFERENCES "_products_v"("id") ON DELETE cascade;
    EXCEPTION WHEN duplicate_object THEN null; END $$
  `);

  // ── 15. Create _pages_v_locales ──────────────────────────────────────────────
  await db.execute(sql`
    CREATE TABLE IF NOT EXISTS "_pages_v_locales" (
      "version_title" varchar, "version_slug" varchar,
      "version_excerpt" varchar, "version_content" jsonb,
      "id" serial PRIMARY KEY NOT NULL,
      "_locale" "enum__locales" NOT NULL, "_parent_id" integer NOT NULL
    )
  `);
  await db.execute(sql`
    DO $$ BEGIN
      ALTER TABLE "_pages_v_locales" ADD CONSTRAINT "_pages_v_locales_locale_parent_id_unique" UNIQUE("_locale", "_parent_id");
    EXCEPTION WHEN duplicate_object THEN null; END $$
  `);
  await db.execute(sql`
    DO $$ BEGIN
      ALTER TABLE "_pages_v_locales" ADD CONSTRAINT "_pages_v_locales_parent_id_fk"
        FOREIGN KEY ("_parent_id") REFERENCES "_pages_v"("id") ON DELETE cascade;
    EXCEPTION WHEN duplicate_object THEN null; END $$
  `);

  // ── 16. Drop the now-redundant old locale enum ───────────────────────────────
  await db.execute(sql`DROP TYPE IF EXISTS "public"."enum_pages_locale"`);
  await db.execute(sql`DROP TYPE IF EXISTS "public"."enum_posts_locale"`);
  await db.execute(sql`DROP TYPE IF EXISTS "public"."enum_products_locale"`);
}

export async function down({ db }: MigrateDownArgs): Promise<void> {
  await db.execute(sql`DROP TABLE IF EXISTS "pages_locales" CASCADE`);
  await db.execute(sql`DROP TABLE IF EXISTS "_pages_v_locales" CASCADE`);
  await db.execute(sql`DROP TABLE IF EXISTS "posts_locales" CASCADE`);
  await db.execute(sql`DROP TABLE IF EXISTS "_posts_v_locales" CASCADE`);
  await db.execute(sql`DROP TABLE IF EXISTS "products_locales" CASCADE`);
  await db.execute(sql`DROP TABLE IF EXISTS "_products_v_locales" CASCADE`);
}
