"use client";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
import * as React from "react";
import Link from "next/link";
import { Mail } from "lucide-react";
import { Button } from "@open-mercato/ui/primitives/button";
import {
  EmailThreadsPanel,
  mergeOptimisticEmailThreads
} from "@open-mercato/ui/backend/messages";
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
import { useGuardedMutation } from "@open-mercato/ui/backend/injection/useGuardedMutation";
import { useAppEvent } from "@open-mercato/ui/backend/injection/useAppEvent";
import { flash } from "@open-mercato/ui/backend/FlashMessages";
import { useT } from "@open-mercato/shared/lib/i18n/context";
import {
  ComposeEmailDialog
} from "./ComposeEmailDialog.js";
const CONTEXT_ID = "customers-person-email-threads";
const MAX_REFERENCES = 40;
const BACKGROUND_POLL_MS = 2e4;
const BURST_INTERVAL_MS = 3e3;
const BURST_DURATION_MS = 36e3;
function resolveReplyRecipient(thread, fallback) {
  for (let i = thread.messages.length - 1; i >= 0; i -= 1) {
    const message = thread.messages[i];
    if (message.direction === "inbound" && message.fromEmail) return message.fromEmail;
  }
  return thread.participants[0] ?? fallback;
}
function buildReplyState(thread, fallbackRecipient) {
  const last = thread.messages[thread.messages.length - 1];
  if (!last) return null;
  const recipient = resolveReplyRecipient(thread, fallbackRecipient);
  const references = Array.from(
    /* @__PURE__ */ new Set([...last.references ?? [], ...last.rfcMessageId ? [last.rfcMessageId] : []])
  ).slice(-MAX_REFERENCES);
  const baseSubject = thread.subject ?? "";
  const subject = /^re:/i.test(baseSubject) ? baseSubject : `Re: ${baseSubject}`.trim();
  return {
    inReplyTo: last.rfcMessageId ?? void 0,
    references: references.length > 0 ? references : void 0,
    to: recipient ? [recipient] : [],
    subject,
    parentMessageId: last.messageId ?? void 0
  };
}
function readEventMessageId(event) {
  const payload = event?.payload;
  const messageId = payload?.messageId;
  return typeof messageId === "string" ? messageId : null;
}
function PersonEmailThreadsTab({ personId, defaultRecipient }) {
  const t = useT();
  const [threads, setThreads] = React.useState([]);
  const [optimistic, setOptimistic] = React.useState([]);
  const [channels, setChannels] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState(null);
  const [dialogOpen, setDialogOpen] = React.useState(false);
  const [replyTo, setReplyTo] = React.useState(null);
  const burstTimer = React.useRef(null);
  const channelsRef = React.useRef([]);
  channelsRef.current = channels;
  const optimisticRef = React.useRef([]);
  optimisticRef.current = optimistic;
  const { runMutation, retryLastMutation } = useGuardedMutation({
    contextId: CONTEXT_ID,
    blockedMessage: t("ui.forms.flash.saveBlocked", "Save blocked by validation")
  });
  const loadThreads = React.useCallback(
    async (opts) => {
      if (opts?.showLoading) setLoading(true);
      try {
        const response = await apiCall(
          `/api/customers/people/${encodeURIComponent(personId)}/email-threads`,
          // Background poll: degrade silently on an expired session instead of
          // hijacking the whole page with a login redirect.
          { method: "GET", headers: { "x-om-forbidden-redirect": "0", "x-om-unauthorized-redirect": "0" } }
        );
        if (!response.ok) {
          const err = response.result;
          throw new Error(err?.error ?? t("customers.email.threads.loadFailed", "Failed to load emails"));
        }
        setThreads(Array.isArray(response.result?.threads) ? response.result.threads : []);
        setError(null);
      } catch (err) {
        setError(err instanceof Error ? err.message : t("customers.email.threads.loadFailed", "Failed to load emails"));
      } finally {
        if (opts?.showLoading) setLoading(false);
      }
    },
    [personId, t]
  );
  const loadChannels = React.useCallback(async () => {
    try {
      const response = await apiCall(
        "/api/communication_channels/me/channels",
        { method: "GET", headers: { "x-om-forbidden-redirect": "0", "x-om-unauthorized-redirect": "0" } }
      );
      const items = Array.isArray(response.result?.items) ? response.result.items : [];
      const connected = items.filter(
        (item) => item !== null && typeof item === "object" && item.status === "connected"
      );
      setChannels(connected);
    } catch {
      setChannels([]);
    }
  }, []);
  const triggerSync = React.useCallback(async () => {
    await Promise.allSettled(
      channelsRef.current.map((channel) => {
        const channelId = channel.id;
        if (!channelId) return Promise.resolve();
        return apiCall(
          `/api/communication_channels/channels/${encodeURIComponent(channelId)}/poll-now`,
          { method: "POST", headers: { "x-om-forbidden-redirect": "0", "x-om-unauthorized-redirect": "0" } }
        );
      })
    );
  }, []);
  const startBurst = React.useCallback(() => {
    if (burstTimer.current) clearInterval(burstTimer.current);
    const startedAt = Date.now();
    burstTimer.current = setInterval(() => {
      if (Date.now() - startedAt > BURST_DURATION_MS) {
        if (burstTimer.current) {
          clearInterval(burstTimer.current);
          burstTimer.current = null;
        }
        return;
      }
      void loadThreads();
    }, BURST_INTERVAL_MS);
  }, [loadThreads]);
  const buildOptimisticMessage = React.useCallback(
    (clientId, messageId, values, status) => {
      const channel = channelsRef.current.find(
        (c) => c.id === values.userChannelId
      );
      return {
        id: `optimistic:${clientId}`,
        messageId,
        rfcMessageId: null,
        references: values.references ?? [],
        direction: "outbound",
        fromName: null,
        fromEmail: channel?.externalIdentifier ?? null,
        to: values.to,
        cc: values.cc ?? [],
        subject: values.subject,
        bodyText: values.body,
        sentAt: (/* @__PURE__ */ new Date()).toISOString(),
        providerKey: channel?.providerKey ?? null,
        status
      };
    },
    []
  );
  const sendEmail = React.useCallback(
    async (values) => {
      const operation = async () => {
        const response = await apiCall(
          `/api/customers/people/${encodeURIComponent(personId)}/emails`,
          {
            method: "POST",
            headers: { "content-type": "application/json" },
            body: JSON.stringify(values)
          }
        );
        if (!response.ok) {
          const err = response.result;
          throw new Error(err?.error ?? t("customers.email.errors.sendFailed", "Send failed"));
        }
        return {
          messageId: response.result?.messageId ?? null,
          threadId: response.result?.threadId ?? null
        };
      };
      const result = await runMutation({
        operation,
        context: {
          formId: CONTEXT_ID,
          resourceKind: "customers.person",
          resourceId: personId,
          retryLastMutation
        },
        mutationPayload: values
      });
      return result ?? { messageId: null, threadId: null };
    },
    [personId, runMutation, retryLastMutation, t]
  );
  const setMessageStatus = React.useCallback(
    (matcher, patch) => {
      setOptimistic(
        (prev) => prev.map(
          (entry) => matcher(entry) ? { ...entry, message: { ...entry.message, ...patch } } : entry
        )
      );
    },
    []
  );
  React.useEffect(() => {
    void loadThreads({ showLoading: true });
    void loadChannels();
  }, [loadThreads, loadChannels]);
  React.useEffect(() => {
    const id = setInterval(() => {
      void loadThreads();
    }, BACKGROUND_POLL_MS);
    return () => clearInterval(id);
  }, [loadThreads]);
  React.useEffect(() => () => {
    if (burstTimer.current) clearInterval(burstTimer.current);
  }, []);
  React.useEffect(() => {
    setOptimistic((prev) => {
      if (prev.length === 0) return prev;
      const serverIds = /* @__PURE__ */ new Set();
      for (const thread of threads) {
        for (const message of thread.messages) {
          if (message.messageId) serverIds.add(message.messageId);
        }
      }
      const next = prev.filter((entry) => !(entry.message.messageId && serverIds.has(entry.message.messageId)));
      return next.length === prev.length ? prev : next;
    });
  }, [threads]);
  useAppEvent("customers.email.linked", () => {
    void loadThreads();
  }, [loadThreads]);
  useAppEvent("messages.message.sent", () => {
    void loadThreads();
  }, [loadThreads]);
  useAppEvent("communication_channels.message.received", () => {
    void loadThreads();
  }, [loadThreads]);
  useAppEvent(
    "communication_channels.message.sent",
    (event) => {
      const messageId = readEventMessageId(event);
      if (messageId) setMessageStatus((e) => e.message.messageId === messageId, { status: "sent" });
      void loadThreads();
    },
    [setMessageStatus, loadThreads]
  );
  useAppEvent(
    "communication_channels.message.delivery_failed",
    (event) => {
      const messageId = readEventMessageId(event);
      if (messageId) {
        setMessageStatus((e) => e.message.messageId === messageId, {
          status: "failed",
          statusError: t("customers.email.errors.deliveryFailed", "Delivery failed \u2014 not sent")
        });
      }
    },
    [setMessageStatus, t]
  );
  const onComposeNew = React.useCallback(() => {
    setReplyTo(null);
    setDialogOpen(true);
  }, []);
  const onReply = React.useCallback(
    (thread) => {
      setReplyTo(buildReplyState(thread, defaultRecipient ?? null));
      setDialogOpen(true);
    },
    [defaultRecipient]
  );
  const onSend = React.useCallback(
    async (values) => {
      const { messageId, threadId } = await sendEmail(values);
      flash(t("customers.email.compose.sent", "Email sent"), "success");
      if (messageId) {
        const clientId = crypto.randomUUID();
        const message = buildOptimisticMessage(clientId, messageId, values, "sending");
        setOptimistic((prev) => [
          ...prev,
          { clientId, threadKey: threadId ?? `optimistic:${clientId}`, values, message }
        ]);
      }
      startBurst();
      return { messageId };
    },
    [sendEmail, t, buildOptimisticMessage, startBurst]
  );
  const onRetry = React.useCallback(
    async (message) => {
      const entry = optimisticRef.current.find((e) => e.message.id === message.id);
      if (!entry) return;
      setMessageStatus((e) => e.message.id === message.id, { status: "sending", statusError: null });
      try {
        const { messageId } = await sendEmail(entry.values);
        setMessageStatus((e) => e.message.id === message.id, { messageId, status: "sending" });
        startBurst();
      } catch (err) {
        setMessageStatus((e) => e.message.id === message.id, {
          status: "failed",
          statusError: err instanceof Error ? err.message : t("customers.email.errors.sendFailed", "Send failed")
        });
      }
    },
    [sendEmail, setMessageStatus, startBurst, t]
  );
  const onRefresh = React.useCallback(async () => {
    setLoading(true);
    try {
      await triggerSync();
      await loadThreads();
    } finally {
      setLoading(false);
    }
    startBurst();
  }, [triggerSync, loadThreads, startBurst]);
  const mergedThreads = React.useMemo(
    () => mergeOptimisticEmailThreads(
      threads,
      optimistic.map((entry) => ({ ...entry.message, threadKey: entry.threadKey }))
    ),
    [threads, optimistic]
  );
  const canCompose = channels.length > 0;
  const composeDisabledHint = /* @__PURE__ */ jsx(Button, { asChild: true, variant: "outline", size: "sm", className: "gap-2", children: /* @__PURE__ */ jsxs(Link, { href: "/backend/profile/communication-channels", children: [
    /* @__PURE__ */ jsx(Mail, { className: "h-4 w-4" }),
    t("customers.email.compose.noChannel.cta", "Connect your mailbox")
  ] }) });
  return /* @__PURE__ */ jsxs(Fragment, { children: [
    /* @__PURE__ */ jsx(
      EmailThreadsPanel,
      {
        threads: mergedThreads,
        loading,
        error,
        canCompose,
        composeDisabledHint,
        onComposeNew,
        onReply,
        onRefresh: () => {
          void onRefresh();
        },
        onRetry: (message) => {
          void onRetry(message);
        }
      }
    ),
    /* @__PURE__ */ jsx(
      ComposeEmailDialog,
      {
        open: dialogOpen,
        onOpenChange: setDialogOpen,
        defaultRecipient,
        channels,
        replyTo,
        onSend
      }
    )
  ] });
}
var PersonEmailThreadsTab_default = PersonEmailThreadsTab;
export {
  PersonEmailThreadsTab,
  PersonEmailThreadsTab_default as default
};
//# sourceMappingURL=PersonEmailThreadsTab.js.map
