import {
  createNavigationItem,
  createNavigationMenu,
  deleteNavigationItem,
  deleteNavigationMenu,
  listNavigationMenus,
  listPages,
  updateNavigationItem,
  updateNavigationMenu,
  upsertNavigationItemTranslation,
} from "@cms/db"
import { Button } from "@cms/ui/button"
import { revalidatePath } from "next/cache"
import { redirect } from "next/navigation"

import { AdminShell } from "@/components/admin-shell"
import { CreateMenuForm } from "@/components/navigation/create-menu-form"
import { CreateNavigationItemForm } from "@/components/navigation/create-navigation-item-form"
import { requirePermissionForRoute } from "@/lib/route-guards"

export const dynamic = "force-dynamic"

type SearchParamsInput = Record<string, string | string[] | undefined>
const SUPPORTED_LOCALES = ["de", "en", "es", "fr"] as const

type SupportedLocale = (typeof SUPPORTED_LOCALES)[number]

function readFirstValue(value: string | string[] | undefined): string | null {
  if (Array.isArray(value)) {
    return value[0] ?? null
  }

  return value ?? null
}

function readInputString(formData: FormData, field: string): string {
  const value = formData.get(field)
  return typeof value === "string" ? value.trim() : ""
}

function readNullableString(formData: FormData, field: string): string | null {
  const value = readInputString(formData, field)
  return value.length > 0 ? value : null
}

function readInt(formData: FormData, field: string, fallback = 0): number {
  const value = readInputString(formData, field)

  if (!value) {
    return fallback
  }

  const parsed = Number.parseInt(value, 10)

  if (!Number.isFinite(parsed)) {
    return fallback
  }

  return parsed
}

function normalizeLocale(input: string | null): SupportedLocale {
  if (input && SUPPORTED_LOCALES.includes(input as SupportedLocale)) {
    return input as SupportedLocale
  }

  return "en"
}

function redirectWithState(params: { notice?: string; error?: string }) {
  const query = new URLSearchParams()

  if (params.notice) {
    query.set("notice", params.notice)
  }

  if (params.error) {
    query.set("error", params.error)
  }

  const value = query.toString()
  redirect(value ? `/navigation?${value}` : "/navigation")
}

async function createMenuAction(formData: FormData) {
  "use server"

  await requirePermissionForRoute({
    nextPath: "/navigation",
    permission: "navigation:write",
    scope: "team",
  })

  try {
    await createNavigationMenu({
      name: readInputString(formData, "name"),
      slug: readInputString(formData, "slug"),
      location: readInputString(formData, "location"),
      isVisible: readInputString(formData, "isVisible") === "true",
    })
  } catch {
    redirectWithState({ error: "Failed to create navigation menu." })
  }

  revalidatePath("/navigation")
  redirectWithState({ notice: "Navigation menu created." })
}

async function createItemAction(formData: FormData) {
  "use server"

  await requirePermissionForRoute({
    nextPath: "/navigation",
    permission: "navigation:write",
    scope: "team",
  })

  try {
    await createNavigationItem({
      menuId: readInputString(formData, "menuId"),
      label: readInputString(formData, "label"),
      href: readNullableString(formData, "href"),
      pageId: readNullableString(formData, "pageId"),
      parentId: readNullableString(formData, "parentId"),
      sortOrder: readInt(formData, "sortOrder", 0),
      isVisible: readInputString(formData, "isVisible") === "true",
    })
  } catch {
    redirectWithState({ error: "Failed to create navigation item." })
  }

  revalidatePath("/navigation")
  redirectWithState({ notice: "Navigation item created." })
}

async function updateMenuAction(formData: FormData) {
  "use server"

  await requirePermissionForRoute({
    nextPath: "/navigation",
    permission: "navigation:write",
    scope: "team",
  })

  try {
    await updateNavigationMenu({
      id: readInputString(formData, "id"),
      name: readInputString(formData, "name"),
      slug: readInputString(formData, "slug"),
      location: readInputString(formData, "location"),
      isVisible: readInputString(formData, "isVisible") === "true",
    })
  } catch {
    redirectWithState({ error: "Failed to update navigation menu." })
  }

  revalidatePath("/navigation")
  redirectWithState({ notice: "Navigation menu updated." })
}

async function deleteMenuAction(formData: FormData) {
  "use server"

  await requirePermissionForRoute({
    nextPath: "/navigation",
    permission: "navigation:write",
    scope: "team",
  })

  try {
    await deleteNavigationMenu(readInputString(formData, "id"))
  } catch {
    redirectWithState({ error: "Failed to delete navigation menu." })
  }

  revalidatePath("/navigation")
  redirectWithState({ notice: "Navigation menu deleted." })
}

async function updateItemAction(formData: FormData) {
  "use server"

  await requirePermissionForRoute({
    nextPath: "/navigation",
    permission: "navigation:write",
    scope: "team",
  })

  try {
    await updateNavigationItem({
      id: readInputString(formData, "id"),
      label: readInputString(formData, "label"),
      href: readNullableString(formData, "href"),
      pageId: readNullableString(formData, "pageId"),
      parentId: readNullableString(formData, "parentId"),
      sortOrder: readInt(formData, "sortOrder", 0),
      isVisible: readInputString(formData, "isVisible") === "true",
    })
  } catch {
    redirectWithState({ error: "Failed to update navigation item." })
  }

  revalidatePath("/navigation")
  redirectWithState({ notice: "Navigation item updated." })
}

async function deleteItemAction(formData: FormData) {
  "use server"

  await requirePermissionForRoute({
    nextPath: "/navigation",
    permission: "navigation:write",
    scope: "team",
  })

  try {
    await deleteNavigationItem(readInputString(formData, "id"))
  } catch {
    redirectWithState({ error: "Failed to delete navigation item." })
  }

  revalidatePath("/navigation")
  redirectWithState({ notice: "Navigation item deleted." })
}

async function upsertItemTranslationAction(formData: FormData) {
  "use server"

  await requirePermissionForRoute({
    nextPath: "/navigation",
    permission: "navigation:write",
    scope: "team",
  })

  const locale = normalizeLocale(readInputString(formData, "locale"))

  try {
    await upsertNavigationItemTranslation({
      navigationItemId: readInputString(formData, "navigationItemId"),
      locale,
      label: readInputString(formData, "label"),
    })
  } catch {
    redirectWithState({ error: "Failed to save item translation." })
  }

  revalidatePath("/navigation")
  redirectWithState({ notice: "Navigation item translation saved." })
}

export default async function NavigationManagementPage({
  searchParams,
}: {
  searchParams: Promise<SearchParamsInput>
}) {
  const role = await requirePermissionForRoute({
    nextPath: "/navigation",
    permission: "navigation:read",
    scope: "team",
  })

  const [resolvedSearchParams, menus, pages] = await Promise.all([
    searchParams,
    listNavigationMenus(),
    listPages(200),
  ])

  const notice = readFirstValue(resolvedSearchParams.notice)
  const error = readFirstValue(resolvedSearchParams.error)
  const selectedLocale = normalizeLocale(readFirstValue(resolvedSearchParams.locale))

  return (
    <AdminShell
      role={role}
      activePath="/navigation"
      badge="Admin App"
      title="Navigation"
      description="Manage menus and navigation entries linked to pages or custom routes."
    >
      {notice ? (
        <section className="rounded-xl border border-emerald-300 bg-emerald-50 px-4 py-3 text-sm text-emerald-800">
          {notice}
        </section>
      ) : null}

      {error ? (
        <section className="rounded-xl border border-red-300 bg-red-50 px-4 py-3 text-sm text-red-800">
          {error}
        </section>
      ) : null}

      <section className="grid gap-4 lg:grid-cols-2">
        <article className="rounded-xl border border-neutral-200 p-6">
          <h2 className="text-xl font-medium">Create Menu</h2>
          <CreateMenuForm action={createMenuAction} />
        </article>

        <article className="rounded-xl border border-neutral-200 p-6">
          <h2 className="text-xl font-medium">Create Navigation Item</h2>
          <CreateNavigationItemForm action={createItemAction} menus={menus} pages={pages} />
        </article>
      </section>

      <section className="space-y-4">
        <div className="flex flex-wrap gap-2">
          {SUPPORTED_LOCALES.map((locale) => (
            <a
              key={locale}
              href={`/navigation?locale=${locale}`}
              className={`inline-flex rounded border px-3 py-1.5 text-xs ${
                selectedLocale === locale
                  ? "border-neutral-800 bg-neutral-900 text-white"
                  : "border-neutral-300 text-neutral-700"
              }`}
            >
              {locale.toUpperCase()}
            </a>
          ))}
        </div>

        {menus.length === 0 ? (
          <article className="rounded-xl border border-neutral-200 p-6 text-sm text-neutral-600">
            No navigation menus yet.
          </article>
        ) : (
          menus.map((menu) => (
            <article key={menu.id} className="rounded-xl border border-neutral-200 p-6">
              <form action={updateMenuAction} className="rounded border border-neutral-200 p-3">
                <input type="hidden" name="id" value={menu.id} />
                <div className="grid gap-3 md:grid-cols-4">
                  <label className="space-y-1">
                    <span className="text-xs text-neutral-600">Menu name</span>
                    <input
                      name="name"
                      defaultValue={menu.name}
                      className="w-full rounded border border-neutral-300 px-3 py-2 text-sm"
                    />
                  </label>
                  <label className="space-y-1">
                    <span className="text-xs text-neutral-600">Slug</span>
                    <input
                      name="slug"
                      defaultValue={menu.slug}
                      className="w-full rounded border border-neutral-300 px-3 py-2 text-sm"
                    />
                  </label>
                  <label className="space-y-1">
                    <span className="text-xs text-neutral-600">Location</span>
                    <input
                      name="location"
                      defaultValue={menu.location}
                      className="w-full rounded border border-neutral-300 px-3 py-2 text-sm"
                    />
                  </label>
                  <label className="space-y-1">
                    <span className="text-xs text-neutral-600">Visible</span>
                    <select
                      name="isVisible"
                      defaultValue={menu.isVisible ? "true" : "false"}
                      className="w-full rounded border border-neutral-300 px-3 py-2 text-sm"
                    >
                      <option value="true">Visible</option>
                      <option value="false">Hidden</option>
                    </select>
                  </label>
                </div>
                <div className="mt-3 flex items-center gap-2">
                  <Button type="submit" size="sm">
                    Save menu
                  </Button>
                  <button
                    type="submit"
                    formAction={deleteMenuAction}
                    className="rounded-md border border-red-300 px-3 py-2 text-sm text-red-700"
                  >
                    Delete menu
                  </button>
                </div>
              </form>

              <div className="mt-4 space-y-3">
                {menu.items.length === 0 ? (
                  <p className="text-sm text-neutral-600">No items in this menu.</p>
                ) : (
                  menu.items.map((item) => {
                    const translation = item.translations.find(
                      (entry) => entry.locale === selectedLocale,
                    )

                    return (
                      <div key={item.id} className="rounded-lg border border-neutral-200 p-3">
                        <form action={updateItemAction}>
                          <input type="hidden" name="id" value={item.id} />
                          <div className="grid gap-3 md:grid-cols-5">
                            <label className="space-y-1 md:col-span-2">
                              <span className="text-xs text-neutral-600">Label</span>
                              <input
                                name="label"
                                defaultValue={item.label}
                                className="w-full rounded border border-neutral-300 px-3 py-2 text-sm"
                              />
                            </label>
                            <label className="space-y-1 md:col-span-2">
                              <span className="text-xs text-neutral-600">Href</span>
                              <input
                                name="href"
                                defaultValue={item.href ?? ""}
                                className="w-full rounded border border-neutral-300 px-3 py-2 text-sm"
                              />
                            </label>
                            <label className="space-y-1">
                              <span className="text-xs text-neutral-600">Sort</span>
                              <input
                                name="sortOrder"
                                type="number"
                                min={0}
                                defaultValue={item.sortOrder}
                                className="w-full rounded border border-neutral-300 px-3 py-2 text-sm"
                              />
                            </label>
                          </div>

                          <div className="mt-3 grid gap-3 md:grid-cols-2">
                            <label className="space-y-1">
                              <span className="text-xs text-neutral-600">Linked page</span>
                              <select
                                name="pageId"
                                defaultValue={item.pageId ?? ""}
                                className="w-full rounded border border-neutral-300 px-3 py-2 text-sm"
                              >
                                <option value="">(none)</option>
                                {pages.map((page) => (
                                  <option key={page.id} value={page.id}>
                                    {page.title} (/{page.slug})
                                  </option>
                                ))}
                              </select>
                            </label>
                            <label className="space-y-1">
                              <span className="text-xs text-neutral-600">Parent id</span>
                              <select
                                name="parentId"
                                defaultValue={item.parentId ?? ""}
                                className="w-full rounded border border-neutral-300 px-3 py-2 text-sm"
                              >
                                <option value="">(none)</option>
                                {menu.items
                                  .filter((entry) => entry.id !== item.id)
                                  .map((entry) => (
                                    <option key={`${item.id}-parent-${entry.id}`} value={entry.id}>
                                      {entry.label}
                                    </option>
                                  ))}
                              </select>
                            </label>
                          </div>

                          <div className="mt-3 flex flex-wrap items-center justify-between gap-3">
                            <label className="inline-flex items-center gap-2 text-sm text-neutral-700">
                              <input
                                type="checkbox"
                                name="isVisible"
                                value="true"
                                defaultChecked={item.isVisible}
                                className="size-4"
                              />
                              Visible
                            </label>
                            <div className="flex items-center gap-2">
                              <Button type="submit" size="sm">
                                Save item
                              </Button>
                              <button
                                type="submit"
                                formAction={deleteItemAction}
                                className="rounded-md border border-red-300 px-3 py-2 text-sm text-red-700"
                              >
                                Delete
                              </button>
                            </div>
                          </div>
                        </form>

                        <form
                          action={upsertItemTranslationAction}
                          className="mt-3 rounded border border-neutral-200 p-3"
                        >
                          <input type="hidden" name="navigationItemId" value={item.id} />
                          <input type="hidden" name="locale" value={selectedLocale} />

                          <p className="text-xs text-neutral-600">
                            Translation ({selectedLocale.toUpperCase()}) - saved locales:{" "}
                            {item.translations.length > 0
                              ? item.translations
                                  .map((entry) => entry.locale.toUpperCase())
                                  .join(", ")
                              : "none"}
                          </p>

                          <div className="mt-2 flex gap-2">
                            <input
                              name="label"
                              defaultValue={translation?.label ?? item.label}
                              className="w-full rounded border border-neutral-300 px-3 py-2 text-sm"
                            />
                            <Button type="submit" size="sm" variant="secondary">
                              Save translation
                            </Button>
                          </div>
                        </form>
                      </div>
                    )
                  })
                )}
              </div>
            </article>
          ))
        )}
      </section>
    </AdminShell>
  )
}
