"use client";
import { jsx, jsxs } from "react/jsx-runtime";
import * as React from "react";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { Button } from "@open-mercato/ui/primitives/button";
import { IconButton } from "@open-mercato/ui/primitives/icon-button";
import { Tabs, TabsList, TabsTrigger } from "@open-mercato/ui/primitives/tabs";
import { Input } from "@open-mercato/ui/primitives/input";
import { ComboboxInput } from "@open-mercato/ui/backend/inputs";
import { LoadingMessage, ErrorMessage } from "@open-mercato/ui/backend/detail";
import { flash } from "@open-mercato/ui/backend/FlashMessages";
import { apiCall, readApiResultOrThrow, withScopedApiRequestHeaders } from "@open-mercato/ui/backend/utils/apiCall";
import { buildOptimisticLockHeader } from "@open-mercato/ui/backend/utils/optimisticLock";
import { surfaceRecordConflict } from "@open-mercato/ui/backend/conflicts";
import { useGuardedMutation } from "@open-mercato/ui/backend/injection/useGuardedMutation";
import { useCustomFieldDefs } from "@open-mercato/ui/backend/utils/customFieldDefs";
import { Save, Plus, X } from "lucide-react";
import { useOrganizationScopeVersion } from "@open-mercato/shared/lib/frontend/useOrganizationScope";
import { useT } from "@open-mercato/shared/lib/i18n/context";
import { locales as defaultLocales } from "@open-mercato/shared/lib/i18n/config";
import { ISO_639_1, isValidIso639, getIso639Label } from "@open-mercato/shared/lib/i18n/iso639";
import { formatEntityLabel, buildEntityListUrl, getRecordLabel, resolveBaseValue } from "../lib/helpers.js";
import { resolveFieldList } from "../lib/resolve-field-list.js";
import { createLogger } from "@open-mercato/shared/lib/logger";
const logger = createLogger("translations").child({ component: "TranslationManager" });
const TRANSLATION_MUTATION_CONTEXT_ID = "translations.entity-translations";
const SUPPORTED_LOCALES_MUTATION_CONTEXT_ID = "translations.supported-locales";
function useTranslationLocales() {
  return useQuery({
    queryKey: ["translation-locales"],
    queryFn: async () => {
      const res = await apiCall("/api/translations/locales");
      if (!res.ok) return [...defaultLocales];
      return Array.isArray(res.result?.locales) && res.result.locales.length > 0 ? res.result.locales : [...defaultLocales];
    },
    staleTime: 6e4
  });
}
function TranslationManager({
  entityType: propEntityType,
  recordId: propRecordId,
  baseValues: propBaseValues,
  translatableFields: propTranslatableFields,
  mode = "standalone",
  compact = false
}) {
  const t = useT();
  const scopeVersion = useOrganizationScopeVersion();
  const isEmbedded = mode === "embedded";
  const [selectedEntityType, setSelectedEntityType] = React.useState(propEntityType ?? "");
  const [selectedRecordId, setSelectedRecordId] = React.useState(propRecordId ?? "");
  const [activeLocale, setActiveLocale] = React.useState("");
  const [editedTranslations, setEditedTranslations] = React.useState({});
  const editedTranslationsRef = React.useRef({});
  const [hasUserEdited, setHasUserEdited] = React.useState(false);
  const hasUserEditedRef = React.useRef(false);
  const entityType = isEmbedded ? propEntityType ?? "" : selectedEntityType;
  const recordId = isEmbedded ? propRecordId ?? "" : selectedRecordId;
  const { data: locales = [...defaultLocales] } = useTranslationLocales();
  React.useEffect(() => {
    if (locales.length > 0 && (!activeLocale || !locales.includes(activeLocale))) {
      setActiveLocale(locales[0]);
    }
  }, [locales, activeLocale]);
  React.useEffect(() => {
    if (isEmbedded && propEntityType) setSelectedEntityType(propEntityType);
  }, [isEmbedded, propEntityType]);
  React.useEffect(() => {
    if (isEmbedded && propRecordId) setSelectedRecordId(propRecordId);
  }, [isEmbedded, propRecordId]);
  const { data: entities, isLoading: loadingEntities, error: entitiesError } = useQuery({
    queryKey: ["entities-list", scopeVersion],
    enabled: !isEmbedded,
    queryFn: async () => readApiResultOrThrow("/api/entities/entities", void 0, {
      errorMessage: t("translations.manager.errors.loadEntities", "Failed to load entities")
    })
  });
  const entitySuggestions = React.useMemo(
    () => (entities?.items || []).map((item) => ({
      value: item.entityId,
      label: formatEntityLabel(item.entityId, item.label),
      description: item.entityId
    })),
    [entities]
  );
  const resolveEntityLabel = React.useCallback(
    (value) => {
      const match = entities?.items?.find((e) => e.entityId === value);
      return match ? formatEntityLabel(match.entityId, match.label) : formatEntityLabel(value);
    },
    [entities]
  );
  const listUrl = React.useMemo(() => entityType ? buildEntityListUrl(entityType) : null, [entityType]);
  const loadRecordSuggestions = React.useCallback(
    async (query) => {
      if (!entityType || !listUrl) return [];
      const url = `${listUrl}?pageSize=20${query ? `&search=${encodeURIComponent(query)}` : ""}`;
      const res = await apiCall(url);
      if (!res.ok) return [];
      const items = res.result?.items ?? [];
      return items.map((item) => ({
        value: String(item.id ?? ""),
        label: getRecordLabel(item)
      }));
    },
    [entityType, listUrl]
  );
  const { data: recordData } = useQuery({
    queryKey: ["translation-record-data", entityType, recordId, listUrl, scopeVersion],
    enabled: !isEmbedded && !!entityType && !!recordId && !!listUrl,
    queryFn: async () => {
      const res = await apiCall(
        // Some APIs filter by `id` (catalog), others by `ids` (resources) — send both so the one recognized by the target route's buildFilters is applied
        `${listUrl}?id=${encodeURIComponent(recordId)}&ids=${encodeURIComponent(recordId)}&pageSize=1`
      );
      if (!res.ok) return null;
      const items = res.result?.items;
      return Array.isArray(items) && items.length > 0 ? items[0] : null;
    }
  });
  const baseValues = isEmbedded ? propBaseValues ?? {} : recordData ?? {};
  const resolveRecordLabel = React.useCallback(
    (value) => {
      if (recordData) return getRecordLabel(recordData);
      return value;
    },
    [recordData]
  );
  const { data: fieldDefs = [], isLoading: loadingFieldDefs } = useCustomFieldDefs(entityType ? [entityType] : [], {
    enabled: !!entityType
  });
  const fieldList = React.useMemo(
    () => resolveFieldList(entityType, propTranslatableFields, fieldDefs),
    [entityType, propTranslatableFields, fieldDefs]
  );
  const {
    data: translationData,
    isLoading: loadingTranslation,
    isError: translationError,
    refetch: refetchTranslation
  } = useQuery({
    queryKey: ["entity-translation", entityType, recordId, scopeVersion],
    enabled: !!entityType && !!recordId,
    queryFn: async () => {
      const res = await apiCall(
        `/api/translations/${encodeURIComponent(entityType)}/${encodeURIComponent(recordId)}`
      );
      if (!res.ok) {
        if (res.response?.status === 404) return null;
        return null;
      }
      return res.result ?? null;
    }
  });
  const translationRowUpdatedAt = React.useMemo(() => {
    const value = translationData?.updatedAt;
    return typeof value === "string" && value.trim().length > 0 ? value : null;
  }, [translationData]);
  const translationSignature = React.useMemo(() => JSON.stringify(translationData ?? null), [translationData]);
  const lastTranslationSignatureRef = React.useRef(null);
  React.useEffect(() => {
    const sig = translationSignature;
    if (sig === lastTranslationSignatureRef.current && hasUserEditedRef.current) return;
    lastTranslationSignatureRef.current = sig;
    if (!translationData?.translations) {
      if (!hasUserEditedRef.current) {
        editedTranslationsRef.current = {};
        setEditedTranslations({});
      }
      return;
    }
    const parsed = {};
    for (const [locale, fields] of Object.entries(translationData.translations)) {
      if (!fields || typeof fields !== "object") continue;
      parsed[locale] = {};
      for (const [key, val] of Object.entries(fields)) {
        parsed[locale][key] = typeof val === "string" ? val : "";
      }
    }
    if (!hasUserEditedRef.current) {
      editedTranslationsRef.current = parsed;
      setEditedTranslations(parsed);
    }
  }, [translationSignature, translationData]);
  const { runMutation, retryLastMutation } = useGuardedMutation({ contextId: TRANSLATION_MUTATION_CONTEXT_ID });
  const mutation = useMutation({
    mutationFn: async () => {
      if (!entityType || !recordId) {
        throw new Error(t("translations.manager.errors.selectRecord", "Select an entity and record before saving"));
      }
      const body = {};
      for (const [locale, fields] of Object.entries(editedTranslationsRef.current)) {
        const localeFields = {};
        let hasValues = false;
        for (const [key, val] of Object.entries(fields)) {
          if (val && val.trim().length > 0) {
            localeFields[key] = val.trim();
            hasValues = true;
          }
        }
        if (hasValues) body[locale] = localeFields;
      }
      if (Object.keys(body).length === 0) {
        logger.warn("Save skipped: payload is empty \u2014 no locale contains any non-empty field");
        throw new Error(t("translations.manager.errors.nothingToSave", "Nothing to save \u2014 enter a translation first"));
      }
      return runMutation({
        operation: async () => {
          const res = await withScopedApiRequestHeaders(
            buildOptimisticLockHeader(translationRowUpdatedAt),
            () => apiCall(
              `/api/translations/${encodeURIComponent(entityType)}/${encodeURIComponent(recordId)}`,
              {
                method: "PUT",
                headers: { "content-type": "application/json" },
                body: JSON.stringify(body)
              }
            )
          );
          if (!res.ok) {
            throw new Error(t("translations.manager.errors.save", "Failed to save translations"));
          }
          return true;
        },
        context: {
          formId: TRANSLATION_MUTATION_CONTEXT_ID,
          entityType,
          recordId,
          resourceKind: "translation",
          resourceId: recordId,
          data: translationData ?? null,
          retryLastMutation
        },
        mutationPayload: body
      });
    },
    onSuccess: () => {
      flash(t("translations.manager.flash.saved", "Translations saved"), "success");
      hasUserEditedRef.current = false;
      setHasUserEdited(false);
      void refetchTranslation();
    },
    onError: (err) => {
      if (surfaceRecordConflict(err, t)) return;
      const message = err instanceof Error ? err.message : t("translations.manager.errors.save", "Failed to save translations");
      flash(message, "error");
    }
  });
  const updateFieldValue = (locale, fieldKey, value) => {
    hasUserEditedRef.current = true;
    setHasUserEdited(true);
    const next = {
      ...editedTranslationsRef.current,
      [locale]: {
        ...editedTranslationsRef.current[locale],
        [fieldKey]: value
      }
    };
    editedTranslationsRef.current = next;
    setEditedTranslations(next);
  };
  const getBaseValue = (fieldKey) => resolveBaseValue(baseValues, fieldKey);
  const renderRecordPicker = () => {
    if (isEmbedded) return null;
    return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
      /* @__PURE__ */ jsx("label", { className: "text-xs text-muted-foreground", children: t("translations.manager.selectRecord", "Select record") }),
      /* @__PURE__ */ jsx(
        ComboboxInput,
        {
          value: selectedRecordId,
          onChange: (next) => {
            setSelectedRecordId(next);
            hasUserEditedRef.current = false;
            setHasUserEdited(false);
          },
          placeholder: t("translations.manager.searchRecords", "Search records..."),
          loadSuggestions: loadRecordSuggestions,
          resolveLabel: resolveRecordLabel,
          allowCustomValues: true,
          disabled: !entityType
        }
      )
    ] });
  };
  const renderLocaleTabs = () => /* @__PURE__ */ jsx(Tabs, { variant: "underline", value: activeLocale, onValueChange: setActiveLocale, children: /* @__PURE__ */ jsx(TabsList, { children: locales.map((locale) => /* @__PURE__ */ jsx(TabsTrigger, { value: locale, children: locale.toUpperCase() }, locale)) }) });
  const renderFieldTable = () => {
    if (!entityType || !recordId) {
      return /* @__PURE__ */ jsx("div", { className: "rounded border bg-background/80 p-4 text-sm text-muted-foreground", children: t("translations.manager.selectFirst", "Select an entity and record to manage translations.") });
    }
    if (loadingTranslation || loadingFieldDefs) {
      return /* @__PURE__ */ jsx(
        LoadingMessage,
        {
          label: t("translations.manager.loadingTranslations", "Loading translations..."),
          className: "border-0 bg-transparent p-4"
        }
      );
    }
    if (translationError) {
      return /* @__PURE__ */ jsx(
        ErrorMessage,
        {
          label: t("translations.manager.errors.loadTranslation", "Failed to load translations"),
          action: /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: () => void refetchTranslation(), children: t("translations.manager.actions.retry", "Retry") })
        }
      );
    }
    if (!fieldList.length) {
      return /* @__PURE__ */ jsx("div", { className: "rounded border bg-background/80 p-4 text-sm text-muted-foreground", children: t("translations.manager.noFields", "No translatable fields found for this entity type.") });
    }
    const localeTranslations = editedTranslations[activeLocale] ?? {};
    return /* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs("table", { className: "w-full min-w-[480px] text-sm", children: [
      /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "text-xs uppercase tracking-wide text-muted-foreground", children: [
        /* @__PURE__ */ jsx("th", { className: "px-3 py-2 text-left w-[140px]", children: t("translations.manager.fields.field", "Field") }),
        !compact && /* @__PURE__ */ jsx("th", { className: "px-3 py-2 text-left", children: t("translations.manager.fields.baseValue", "Base value") }),
        /* @__PURE__ */ jsxs("th", { className: "px-3 py-2 text-left", children: [
          t("translations.manager.fields.translation", "Translation"),
          " (",
          activeLocale.toUpperCase(),
          ")"
        ] })
      ] }) }),
      /* @__PURE__ */ jsx("tbody", { children: fieldList.map((field) => {
        const baseVal = getBaseValue(field.key);
        const translatedVal = localeTranslations[field.key] ?? "";
        return /* @__PURE__ */ jsxs("tr", { className: "border-t", children: [
          /* @__PURE__ */ jsx("td", { className: "px-3 py-2 align-top text-xs font-medium text-muted-foreground", children: field.label }),
          !compact && /* @__PURE__ */ jsx("td", { className: "px-3 py-2 align-top text-xs text-muted-foreground max-w-[200px]", children: baseVal ? /* @__PURE__ */ jsx("span", { className: "line-clamp-3", children: baseVal }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/50", children: "-" }) }),
          /* @__PURE__ */ jsx("td", { className: "px-3 py-2 align-top", children: field.multiline ? /* @__PURE__ */ jsx(
            "textarea",
            {
              className: "flex w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
              rows: 3,
              value: translatedVal,
              onChange: (e) => updateFieldValue(activeLocale, field.key, e.target.value),
              placeholder: baseVal || field.label
            }
          ) : /* @__PURE__ */ jsx(
            Input,
            {
              value: translatedVal,
              onChange: (e) => updateFieldValue(activeLocale, field.key, e.target.value),
              placeholder: baseVal || field.label
            }
          ) })
        ] }, field.key);
      }) })
    ] }) });
  };
  React.useEffect(() => {
    const handler = (e) => {
      if ((e.metaKey || e.ctrlKey) && e.key === "Enter") {
        e.preventDefault();
        if (entityType && recordId && !mutation.isPending) mutation.mutate();
      }
    };
    document.addEventListener("keydown", handler);
    return () => document.removeEventListener("keydown", handler);
  }, [entityType, recordId, mutation]);
  if (compact) {
    return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
      renderLocaleTabs(),
      renderFieldTable(),
      /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxs(
        Button,
        {
          type: "button",
          size: "sm",
          onClick: () => mutation.mutate(),
          disabled: mutation.isPending || !entityType || !recordId,
          "data-testid": "translations-save",
          children: [
            /* @__PURE__ */ jsx(Save, { className: "mr-2 h-3 w-3" }),
            mutation.isPending ? t("translations.manager.actions.saving", "Saving...") : t("translations.manager.actions.save", "Save translations")
          ]
        }
      ) })
    ] });
  }
  return /* @__PURE__ */ jsx("div", { className: "space-y-6", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 rounded-lg border bg-card p-4 shadow-sm", children: [
    /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
      /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold", children: t("translations.manager.title", "Translations") }),
      /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("translations.manager.description", "Manage translations for entity records across supported locales.") })
    ] }),
    !isEmbedded && /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-4 sm:flex-row sm:items-start", children: /* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-3", children: [
      /* @__PURE__ */ jsxs("div", { children: [
        /* @__PURE__ */ jsx("label", { className: "text-xs text-muted-foreground", children: t("translations.manager.selectEntity", "Choose entity") }),
        /* @__PURE__ */ jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsx(
          ComboboxInput,
          {
            value: selectedEntityType,
            onChange: (next) => {
              setSelectedEntityType(next);
              setSelectedRecordId("");
              hasUserEditedRef.current = false;
              setHasUserEdited(false);
            },
            placeholder: t("translations.manager.placeholder", "Select an entity"),
            suggestions: entitySuggestions,
            resolveLabel: resolveEntityLabel,
            disabled: loadingEntities || !!entitiesError
          }
        ) }),
        entitiesError && /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-destructive", children: t("translations.manager.errors.loadEntities", "Failed to load entities") })
      ] }),
      renderRecordPicker()
    ] }) }),
    /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-background/80 p-4", children: [
      renderLocaleTabs(),
      /* @__PURE__ */ jsx("div", { className: "mt-3", children: renderFieldTable() })
    ] }),
    /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxs(
      Button,
      {
        type: "button",
        onClick: () => mutation.mutate(),
        disabled: mutation.isPending || loadingEntities || !!entitiesError || !entityType || !recordId,
        "data-testid": "translations-save",
        children: [
          /* @__PURE__ */ jsx(Save, { className: "mr-2 h-4 w-4" }),
          mutation.isPending ? t("translations.manager.actions.saving", "Saving...") : t("translations.manager.actions.save", "Save translations")
        ]
      }
    ) })
  ] }) });
}
function LocaleManager() {
  const t = useT();
  const queryClient = useQueryClient();
  const { data: locales = [], isLoading } = useTranslationLocales();
  const [newLocale, setNewLocale] = React.useState("");
  const { runMutation, retryLastMutation } = useGuardedMutation({ contextId: SUPPORTED_LOCALES_MUTATION_CONTEXT_ID });
  const mutation = useMutation({
    mutationFn: async (updatedLocales) => {
      return runMutation({
        operation: async () => {
          const res = await apiCall("/api/translations/locales", {
            method: "PUT",
            headers: { "content-type": "application/json" },
            body: JSON.stringify({ locales: updatedLocales })
          });
          if (!res.ok) throw new Error("Failed to save locales");
          return res.result?.locales ?? updatedLocales;
        },
        context: {
          formId: SUPPORTED_LOCALES_MUTATION_CONTEXT_ID,
          resourceKind: "translation-locales",
          retryLastMutation
        },
        mutationPayload: { locales: updatedLocales }
      });
    },
    onSuccess: (result) => {
      queryClient.setQueryData(["translation-locales"], result);
      flash(t("translations.locales.flash.saved", "Locales updated"), "success");
    },
    onError: () => {
      flash(t("translations.locales.flash.error", "Failed to update locales"), "error");
    }
  });
  const availableLocales = React.useMemo(
    () => ISO_639_1.filter((entry) => !locales.includes(entry.code)).map((entry) => ({
      value: entry.code,
      label: `${entry.code.toUpperCase()} \u2014 ${entry.label}`
    })),
    [locales]
  );
  const addLocale = () => {
    const code = newLocale.toLowerCase().trim();
    if (!code || !isValidIso639(code) || locales.includes(code)) return;
    mutation.mutate([...locales, code]);
    setNewLocale("");
  };
  const removeLocale = (locale) => {
    if (locales.length <= 1) return;
    mutation.mutate(locales.filter((l) => l !== locale));
  };
  if (isLoading) {
    return /* @__PURE__ */ jsx(LoadingMessage, { label: t("translations.locales.loading", "Loading locales..."), className: "border-0 bg-transparent p-4" });
  }
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 rounded-lg border bg-card p-4 shadow-sm", children: [
    /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
      /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold", children: t("translations.locales.title", "Supported locales") }),
      /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("translations.locales.description", "Configure which locales are available for translations. Add ISO language codes (e.g. fr, it, ja, zh).") })
    ] }),
    /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: locales.map((locale) => /* @__PURE__ */ jsxs(
      "span",
      {
        className: "inline-flex items-center gap-1.5 rounded-full border bg-muted/50 px-3 py-1 text-sm font-medium",
        title: getIso639Label(locale) ?? locale,
        children: [
          locale.toUpperCase(),
          getIso639Label(locale) ? ` \u2014 ${getIso639Label(locale)}` : "",
          locales.length > 1 && /* @__PURE__ */ jsx(
            IconButton,
            {
              variant: "ghost",
              size: "xs",
              fullRadius: true,
              "aria-label": t("translations.locales.remove", "Remove {{locale}}", { locale: getIso639Label(locale) ?? locale.toUpperCase() }),
              title: t("translations.locales.remove", "Remove {{locale}}", { locale: getIso639Label(locale) ?? locale.toUpperCase() }),
              onClick: () => removeLocale(locale),
              disabled: mutation.isPending,
              children: /* @__PURE__ */ jsx(X, { className: "h-3 w-3" })
            }
          )
        ]
      },
      locale
    )) }),
    /* @__PURE__ */ jsxs("div", { className: "flex gap-2 items-center", children: [
      /* @__PURE__ */ jsx("div", { className: "max-w-[240px] flex-1", children: /* @__PURE__ */ jsx(
        ComboboxInput,
        {
          value: newLocale,
          onChange: setNewLocale,
          placeholder: t("translations.locales.addPlaceholder", "Search language..."),
          suggestions: availableLocales,
          resolveLabel: (value) => {
            const label = getIso639Label(value);
            return label ? `${value.toUpperCase()} \u2014 ${label}` : value.toUpperCase();
          }
        }
      ) }),
      /* @__PURE__ */ jsxs(
        Button,
        {
          variant: "outline",
          size: "sm",
          onClick: addLocale,
          disabled: mutation.isPending || !newLocale.trim() || !isValidIso639(newLocale) || locales.includes(newLocale.toLowerCase().trim()),
          children: [
            /* @__PURE__ */ jsx(Plus, { className: "mr-1 h-3 w-3" }),
            t("translations.locales.add", "Add")
          ]
        }
      )
    ] })
  ] });
}
export {
  LocaleManager,
  TranslationManager
};
//# sourceMappingURL=TranslationManager.js.map
