"use client";
import { jsx, jsxs } from "react/jsx-runtime";
import * as React from "react";
import { useQuery, useMutation } from "@tanstack/react-query";
import { Button } from "@open-mercato/ui/primitives/button";
import { Checkbox } from "@open-mercato/ui/primitives/checkbox";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue
} from "@open-mercato/ui/primitives/select";
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 { raiseCrudError } from "@open-mercato/ui/backend/utils/serverErrors";
import { useGuardedMutation } from "@open-mercato/ui/backend/injection/useGuardedMutation";
import { buildOptimisticLockHeader } from "@open-mercato/ui/backend/utils/optimisticLock";
import { useCustomFieldDefs } from "@open-mercato/ui/backend/utils/customFieldDefs";
import { Plus, Save, Trash2 } from "lucide-react";
import { useOrganizationScopeVersion } from "@open-mercato/shared/lib/frontend/useOrganizationScope";
import { useT } from "@open-mercato/shared/lib/i18n/context";
import { getEntityFields } from "../../../generated-shims/entity-fields-registry.js";
import { createLogger } from "@open-mercato/shared/lib/logger";
const logger = createLogger("entities").child({ component: "EncryptionManager" });
const EMPTY_FIELD_DEFS = [];
function normalizeToken(value) {
  return value.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-z0-9]/gi, "").toLowerCase();
}
function canonicalizeFieldName(raw, options) {
  const trimmed = typeof raw === "string" ? raw.trim() : "";
  if (!trimmed) return "";
  const normalized = normalizeToken(trimmed);
  for (const option of options) {
    const optionValue = typeof option.value === "string" ? option.value.trim() : "";
    if (optionValue && normalizeToken(optionValue) === normalized) return optionValue;
    if (option.label && normalizeToken(option.label) === normalized) return optionValue;
  }
  return trimmed;
}
function normalizeFieldRows(raw, options) {
  const rows = Array.isArray(raw?.fields) ? raw.fields : [];
  return rows.map((entry, idx) => ({
    id: `${entry.field}-${idx}`,
    field: canonicalizeFieldName(entry.field, options),
    hashField: entry.hashField ? canonicalizeFieldName(entry.hashField, options) : null
  }));
}
function areFieldRowsEqual(a, b) {
  if (a === b) return true;
  if (a.length !== b.length) return false;
  return a.every((row, idx) => {
    const other = b[idx];
    return !!other && row.id === other.id && row.field === other.field && (row.hashField ?? null) === (other.hashField ?? null);
  });
}
function areFieldOptionsEqual(a, b) {
  if (a === b) return true;
  if (a.length !== b.length) return false;
  return a.every((option, idx) => {
    const other = b[idx];
    return !!other && option.value === other.value && option.label === other.label;
  });
}
function buildRowId() {
  if (typeof crypto !== "undefined" && crypto.randomUUID) return crypto.randomUUID();
  return `row-${Math.random().toString(36).slice(2)}`;
}
function EncryptionManager() {
  const t = useT();
  const scopeVersion = useOrganizationScopeVersion();
  const [selectedEntityId, setSelectedEntityId] = React.useState("");
  const [fields, setFields] = React.useState([]);
  const [isActive, setIsActive] = React.useState(true);
  const [baseFieldOptions, setBaseFieldOptions] = React.useState([]);
  const [hasUserEdited, setHasUserEdited] = React.useState(false);
  const { data: rawFieldDefs, isLoading: loadingFieldDefs } = useCustomFieldDefs(selectedEntityId ? [selectedEntityId] : [], {
    enabled: !!selectedEntityId
  });
  const fieldDefs = rawFieldDefs ?? EMPTY_FIELD_DEFS;
  const canonicalOptions = React.useMemo(() => {
    const options = [];
    for (const option of baseFieldOptions) {
      if (!option.value) continue;
      if (options.some((opt) => opt.value === option.value)) continue;
      options.push(option);
    }
    for (const def of fieldDefs) {
      const key = typeof def.key === "string" ? def.key.trim() : "";
      if (!key || options.some((opt) => opt.value === key)) continue;
      const label = typeof def.label === "string" ? def.label : void 0;
      options.push({ value: key, label });
    }
    return options;
  }, [baseFieldOptions, fieldDefs]);
  const fieldOptions = React.useMemo(() => {
    const entries = /* @__PURE__ */ new Map();
    for (const option of baseFieldOptions) {
      if (!option.value || entries.has(option.value)) continue;
      entries.set(option.value, option.label || option.value);
    }
    for (const def of fieldDefs) {
      const key = typeof def.key === "string" ? def.key.trim() : "";
      if (!key || entries.has(key)) continue;
      const label = typeof def.label === "string" && def.label.trim().length ? def.label : key;
      entries.set(key, label);
    }
    for (const row of fields) {
      const main = row.field?.trim();
      if (main && !entries.has(main)) entries.set(main, main);
      const hash = row.hashField?.trim();
      if (hash && !entries.has(hash)) entries.set(hash, hash);
    }
    return Array.from(entries.entries()).map(([value, label]) => ({ value, label }));
  }, [baseFieldOptions, fieldDefs, fields]);
  const { data: entities, isLoading: loadingEntities, error: entitiesError } = useQuery({
    queryKey: ["entities-list", scopeVersion],
    queryFn: async () => readApiResultOrThrow("/api/entities/entities", void 0, {
      errorMessage: t("entities.encryption.errors.loadEntities", "Failed to load entities")
    })
  });
  React.useEffect(() => {
    if (!selectedEntityId && entities?.items?.length) {
      const first = entities.items[0];
      setSelectedEntityId(first.entityId);
    }
  }, [entities, selectedEntityId]);
  React.useEffect(() => {
    if (!selectedEntityId) {
      setBaseFieldOptions((prev) => prev.length ? [] : prev);
      return;
    }
    const parts = selectedEntityId.split(":");
    const entitySlug = parts[1];
    if (!entitySlug) {
      setBaseFieldOptions((prev) => prev.length ? [] : prev);
      return;
    }
    const mod = getEntityFields(entitySlug);
    if (!mod) {
      logger.warn("No fields found for entity", { entitySlug });
      setBaseFieldOptions((prev) => prev.length ? [] : prev);
      return;
    }
    const options = [];
    for (const raw of Object.values(mod)) {
      if (typeof raw !== "string" || !raw.trim()) continue;
      const value = raw.trim();
      if (options.some((opt) => opt.value === value)) continue;
      const label = value.split("_").map((segment) => segment ? `${segment[0].toUpperCase()}${segment.slice(1)}` : "").join(" ").trim() || value;
      options.push({ value, label });
    }
    setBaseFieldOptions((prev) => areFieldOptionsEqual(prev, options) ? prev : options);
  }, [selectedEntityId]);
  const {
    data: map,
    isLoading: loadingMap,
    isError: mapError,
    refetch: refetchMap
  } = useQuery({
    queryKey: ["encryption-map", selectedEntityId, scopeVersion],
    enabled: !!selectedEntityId,
    queryFn: async () => readApiResultOrThrow(`/api/entities/encryption?entityId=${encodeURIComponent(selectedEntityId)}`, void 0, {
      errorMessage: t("entities.encryption.errors.loadMap", "Failed to load encryption map")
    })
  });
  const mapSignature = React.useMemo(() => JSON.stringify(map ?? null), [map]);
  const lastMapSignatureRef = React.useRef(null);
  React.useEffect(() => {
    const signature = mapSignature;
    const isSameMap = signature === lastMapSignatureRef.current;
    if (isSameMap && hasUserEdited) return;
    if (!map) {
      setFields((prev) => prev.length ? [] : prev);
      setIsActive((prev) => prev === true ? prev : true);
      setHasUserEdited(false);
      lastMapSignatureRef.current = signature;
      return;
    }
    const nextFields = normalizeFieldRows(map, canonicalOptions);
    setFields((prev) => areFieldRowsEqual(prev, nextFields) ? prev : nextFields);
    const nextIsActive = map?.isActive !== false;
    setIsActive((prev) => prev === nextIsActive ? prev : nextIsActive);
    setHasUserEdited(false);
    lastMapSignatureRef.current = signature;
  }, [mapSignature, map, canonicalOptions, hasUserEdited]);
  const { runMutation } = useGuardedMutation({ contextId: "entities.encryption-map" });
  const mutation = useMutation({
    mutationFn: async () => {
      const trimmed = fields.map((row) => ({
        field: canonicalizeFieldName(row.field, canonicalOptions).trim(),
        hashField: row.hashField ? canonicalizeFieldName(row.hashField, canonicalOptions).trim() : ""
      })).filter((row) => row.field.length > 0).map((row) => ({
        field: row.field,
        hashField: row.hashField ? row.hashField : null
      }));
      if (!selectedEntityId) {
        throw new Error(t("entities.encryption.errors.selectEntity", "Select an entity before saving"));
      }
      if (!trimmed.length) {
        throw new Error(t("entities.encryption.errors.noFields", "Add at least one field to encrypt"));
      }
      const payload = { entityId: selectedEntityId, fields: trimmed, isActive };
      return runMutation({
        operation: async () => {
          const res = await withScopedApiRequestHeaders(
            buildOptimisticLockHeader(map?.updatedAt ?? null),
            () => apiCall("/api/entities/encryption", {
              method: "POST",
              headers: { "content-type": "application/json" },
              body: JSON.stringify(payload)
            })
          );
          if (!res.ok) {
            await raiseCrudError(res.response, t("entities.encryption.errors.save", "Failed to save encryption map"));
          }
          return true;
        },
        context: {},
        mutationPayload: payload
      });
    },
    onSuccess: () => {
      flash(t("entities.encryption.flash.saved", "Encryption map saved"), "success");
      void refetchMap();
    },
    onError: (err) => {
      const message = err?.message || t("entities.encryption.errors.save", "Failed to save encryption map");
      flash(message, "error");
    }
  });
  const addField = () => {
    setHasUserEdited(true);
    setFields((prev) => [...prev, { id: buildRowId(), field: "", hashField: null }]);
  };
  const updateField = (id, patch) => {
    setHasUserEdited(true);
    setFields((prev) => prev.map((row) => row.id === id ? { ...row, ...patch } : row));
  };
  const removeField = (id) => {
    setHasUserEdited(true);
    setFields((prev) => prev.filter((row) => row.id !== id));
  };
  const renderFields = () => {
    if (loadingMap || loadingFieldDefs) {
      return /* @__PURE__ */ jsx(
        LoadingMessage,
        {
          label: t("entities.encryption.loading", "Loading encryption map\u2026"),
          className: "border-0 bg-transparent p-4"
        }
      );
    }
    if (mapError) {
      return /* @__PURE__ */ jsx(
        ErrorMessage,
        {
          label: t("entities.encryption.errors.loadMap", "Failed to load encryption map"),
          action: /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => void refetchMap(), children: t("entities.encryption.actions.retry", "Retry") })
        }
      );
    }
    if (!fields.length) {
      return /* @__PURE__ */ jsx("div", { className: "rounded border bg-background/80 p-4 text-sm text-muted-foreground", children: t("entities.encryption.empty", "No fields are encrypted yet. Add the first one below.") });
    }
    const withFallbackOption = (value) => {
      if (value && !fieldOptions.some((opt) => opt.value === value)) {
        return [...fieldOptions, { value, label: value }];
      }
      return fieldOptions;
    };
    return /* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs("table", { className: "w-full min-w-[720px] 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", children: t("entities.encryption.fields.field", "Field name") }),
        /* @__PURE__ */ jsx("th", { className: "px-3 py-2 text-left", children: t("entities.encryption.fields.hash", "Hash field (optional)") }),
        /* @__PURE__ */ jsx("th", { className: "px-3 py-2 text-right", children: t("entities.encryption.fields.actions", "Actions") })
      ] }) }),
      /* @__PURE__ */ jsx("tbody", { children: fields.map((row) => {
        const fieldOpts = withFallbackOption(row.field);
        const hashOpts = withFallbackOption(row.hashField);
        return /* @__PURE__ */ jsxs("tr", { className: "border-t", children: [
          /* @__PURE__ */ jsx("td", { className: "px-3 py-2 align-top", children: /* @__PURE__ */ jsxs(
            Select,
            {
              value: row.field || void 0,
              onValueChange: (value) => updateField(row.id, { field: value ?? "" }),
              children: [
                /* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { placeholder: t("entities.encryption.fields.selectField", "Select field") }) }),
                /* @__PURE__ */ jsx(SelectContent, { children: fieldOpts.map((option) => /* @__PURE__ */ jsx(SelectItem, { value: option.value, children: option.label }, option.value)) })
              ]
            }
          ) }),
          /* @__PURE__ */ jsxs("td", { className: "px-3 py-2 align-top", children: [
            /* @__PURE__ */ jsxs(
              Select,
              {
                value: row.hashField || void 0,
                onValueChange: (value) => updateField(row.id, { hashField: value || null }),
                children: [
                  /* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { placeholder: t("entities.encryption.fields.selectHash", "Select hash field (optional)") }) }),
                  /* @__PURE__ */ jsx(SelectContent, { children: hashOpts.map((option) => /* @__PURE__ */ jsx(SelectItem, { value: option.value, children: option.label }, option.value)) })
                ]
              }
            ),
            /* @__PURE__ */ jsx("p", { className: "mt-1 text-overline text-muted-foreground", children: t("entities.encryption.fields.hashHint", "Use when lookups must stay deterministic (e.g., login by email).") })
          ] }),
          /* @__PURE__ */ jsx("td", { className: "px-3 py-2 align-top text-right", children: /* @__PURE__ */ jsx(
            Button,
            {
              type: "button",
              variant: "ghost",
              size: "sm",
              className: "h-9 w-9 px-0",
              "aria-label": t("entities.encryption.actions.remove", "Remove"),
              onClick: () => removeField(row.id),
              children: /* @__PURE__ */ jsx(Trash2, { className: "h-4 w-4" })
            }
          ) })
        ] }, row.id);
      }) })
    ] }) });
  };
  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("entities.encryption.title", "Encryption") }),
      /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("entities.encryption.description", "Manage which entity fields are encrypted with tenant keys and optional hash columns.") })
    ] }),
    /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-4 sm:flex-row sm:items-end", 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("entities.encryption.selectEntity", "Choose entity") }),
        /* @__PURE__ */ jsxs(
          Select,
          {
            value: selectedEntityId || void 0,
            onValueChange: (value) => setSelectedEntityId(value ?? ""),
            disabled: loadingEntities || !!entitiesError,
            children: [
              /* @__PURE__ */ jsx(SelectTrigger, { className: "mt-1", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: t("entities.encryption.placeholder", "Select an entity") }) }),
              /* @__PURE__ */ jsx(SelectContent, { children: (entities?.items || []).map((item) => /* @__PURE__ */ jsxs(SelectItem, { value: item.entityId, children: [
                item.label || item.entityId,
                " ",
                item.source === "custom" ? `(${t("entities.encryption.source.custom", "custom")})` : ""
              ] }, item.entityId)) })
            ]
          }
        ),
        entitiesError ? /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-status-error-text", children: t("entities.encryption.errors.loadEntities", "Failed to load entities") }) : /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: t("entities.encryption.entityHint", "Maps apply per tenant/organization. Use field names from your entities.") })
      ] }),
      /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-2 text-sm", children: [
        /* @__PURE__ */ jsx(
          Checkbox,
          {
            id: "entities-encryption-active",
            checked: isActive,
            onCheckedChange: (checked) => setIsActive(checked === true)
          }
        ),
        /* @__PURE__ */ jsx("label", { htmlFor: "entities-encryption-active", children: t("entities.encryption.active", "Encryption enabled for this entity") })
      ] })
    ] }) }),
    /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-background/80 p-4", children: [
      /* @__PURE__ */ jsxs("div", { className: "mb-3 flex items-center justify-between", children: [
        /* @__PURE__ */ jsxs("div", { children: [
          /* @__PURE__ */ jsx("h3", { className: "text-sm font-medium", children: t("entities.encryption.fields.title", "Encrypted fields") }),
          /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: t("entities.encryption.fields.subtitle", "List the attributes that should be encrypted with the tenant key.") })
        ] }),
        /* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: addField, children: [
          /* @__PURE__ */ jsx(Plus, { className: "mr-2 h-4 w-4" }),
          t("entities.encryption.actions.add", "Add field")
        ] })
      ] }),
      renderFields()
    ] }),
    /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxs(
      Button,
      {
        type: "button",
        onClick: () => mutation.mutate(),
        disabled: mutation.isPending || loadingEntities || !!entitiesError || !selectedEntityId,
        children: [
          /* @__PURE__ */ jsx(Save, { className: "mr-2 h-4 w-4" }),
          mutation.isPending ? t("entities.encryption.actions.saving", "Saving\u2026") : t("entities.encryption.actions.save", "Save encryption map")
        ]
      }
    ) })
  ] }) });
}
export {
  EncryptionManager
};
//# sourceMappingURL=EncryptionManager.js.map
