'use client';

import { useState, useEffect, useRef } from 'react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { HydratedIsland } from '@/components/HydratedIsland';
import { useLocale, useT } from '@/lib/i18n/react';
import type { Locale } from '@/lib/i18n';
import { getCsrfToken } from '@/lib/csrf';
import { captureCaught } from '@/lib/observability';
import { formatRelative } from '@/lib/format';
import { VendorShell } from '@/components/ui/layout/VendorShell';
import { Stack } from '@/components/ui/layout/Stack';
import { ErrorState } from '@/components/ui/feedback/ErrorState';
import { Button } from '@/components/ui/primitives/Button';
import { Textarea } from '@/components/ui/primitives/Textarea';
import type { VendorPurchaseMessageItem } from '@/pages/api/vendor/purchase-messages';

interface ClientPurchaseMessage {
  id: string;
  senderType: 'USER' | 'VENDOR';
  body: string;
  readAt: string | null;
  createdAt: string;
}

interface ThreadPanelProps {
  purchaseId: string;
}

function ThreadPanel({ purchaseId }: ThreadPanelProps) {
  const t = useT('vendor_messages');
  const { locale } = useLocale();
  const qc = useQueryClient();
  const [body, setBody] = useState('');
  const [sendError, setSendError] = useState(false);
  const bottomRef = useRef<HTMLDivElement>(null);
  const ownRole = 'VENDOR' as const;

  const { data, isLoading, isError, refetch } = useQuery<{ messages: ClientPurchaseMessage[] }>({
    queryKey: ['purchase-messages', purchaseId],
    queryFn: async () => {
      const res = await fetch(`/api/purchases/${purchaseId}/messages`);
      const json = (await res.json()) as { ok: boolean; messages?: ClientPurchaseMessage[] };
      if (!json.ok) throw new Error('fetch-messages-failed');
      return { messages: json.messages ?? [] };
    },
    refetchInterval: 30_000,
  });

  const sendMutation = useMutation({
    mutationFn: async (messageBody: string) => {
      const res = await fetch(`/api/purchases/${purchaseId}/messages`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'x-csrf-token': getCsrfToken(),
        },
        body: JSON.stringify({ body: messageBody }),
      });
      const json = (await res.json()) as { ok: boolean };
      if (!json.ok) throw new Error('send-message-failed');
    },
    onSuccess: () => {
      setBody('');
      setSendError(false);
      void qc.invalidateQueries({ queryKey: ['purchase-messages', purchaseId] });
      void qc.invalidateQueries({ queryKey: ['vendor-purchase-messages'] });
    },
    onError: (err) => {
      captureCaught(err, {
        scope: 'features.vendor-messages.VendorPurchaseInbox.send',
        severity: 'warning',
      });
      setSendError(true);
    },
  });

  useEffect(() => {
    fetch(`/api/purchases/${purchaseId}/messages/read`, {
      method: 'POST',
      headers: { 'x-csrf-token': getCsrfToken() },
    })
      .then((res) => {
        if (res.ok) {
          void qc.invalidateQueries({ queryKey: ['vendor-purchase-messages'] });
        }
      })
      .catch((err) =>
        captureCaught(err, {
          scope: 'features.vendor-messages.VendorPurchaseInbox.markRead',
          severity: 'info',
        }),
      );
  }, [purchaseId, qc]);

  useEffect(() => {
    bottomRef.current?.scrollIntoView({ behavior: 'smooth' });
  }, [data?.messages]);

  const messages = data?.messages ?? [];

  if (isError) {
    return (
      <ErrorState
        title={t('error_inbox')}
        action={
          <Button variant="secondary" size="sm" onClick={() => refetch()}>
            {t('retry')}
          </Button>
        }
      />
    );
  }

  return (
    <div className="mt-2">
      <div className="mb-2 flex justify-end">
        <a
          href={`/vendor/orders/${purchaseId}`}
          className="text-brand-primary-600 hover:text-brand-primary-700 text-xs font-medium underline-offset-2 hover:underline"
        >
          {t('view_order')}
        </a>
      </div>

      <div
        className="border-border-default bg-surface-subtle mb-2 flex max-h-64 flex-col gap-2 overflow-y-auto rounded-xl border p-3"
        role="log"
        aria-live="polite"
      >
        {isLoading && (
          <p className="text-text-muted text-center text-xs" role="status" aria-live="polite">
            {t('loading')}
          </p>
        )}
        {!isLoading && messages.length === 0 && (
          <p className="text-text-muted text-center text-sm">{t('empty_thread')}</p>
        )}
        {messages.map((msg) => {
          const isOwn = msg.senderType === ownRole;
          const senderLabel = isOwn ? t('sender_you') : t('sender_customer');
          return (
            <div key={msg.id} className={`flex ${isOwn ? 'justify-end' : 'justify-start'}`}>
              <div
                className={`max-w-[75%] rounded-2xl px-3 py-2 text-sm ${
                  isOwn ? 'bg-brand-primary-600 text-white' : 'bg-surface-raised text-text-primary'
                }`}
                aria-label={senderLabel}
              >
                <span className="sr-only">{senderLabel}</span>
                <p className="break-words">{msg.body}</p>
                {msg.createdAt && (
                  <p className="mt-1 text-end text-xs tabular-nums opacity-60">
                    {formatRelative(msg.createdAt, locale)}
                  </p>
                )}
              </div>
            </div>
          );
        })}
        <div ref={bottomRef} />
      </div>

      {/* Composer */}
      <div className="flex flex-col gap-1">
        <div className="flex items-end gap-2">
          <Textarea
            className="flex-1 resize-none"
            rows={2}
            placeholder={t('reply_placeholder')}
            value={body}
            onChange={(e) => {
              setBody(e.target.value);
              if (sendError) setSendError(false);
            }}
            onKeyDown={(e) => {
              if (e.key === 'Enter' && !e.shiftKey && body.trim()) {
                e.preventDefault();
                sendMutation.mutate(body.trim());
              }
            }}
            disabled={sendMutation.isPending}
          />
          <Button
            variant="primary"
            size="sm"
            disabled={!body.trim() || sendMutation.isPending}
            onClick={() => {
              if (body.trim()) sendMutation.mutate(body.trim());
            }}
          >
            {t('send')}
          </Button>
        </div>
        <p className="text-text-muted text-xs">{t('composer_hint')}</p>
        {sendError && (
          <p role="alert" className="text-feedback-error text-sm">
            {t('send_error')}
          </p>
        )}
      </div>
    </div>
  );
}

function formatUnreadBadge(count: number, t: ReturnType<typeof useT<'vendor_messages'>>): string {
  if (count === 1) return t('unread_badge_one');
  return t('unread_badge').replace('{n}', String(count));
}

function VendorPurchaseInboxInner() {
  const t = useT('vendor_messages');
  const { locale } = useLocale();
  const [expanded, setExpanded] = useState<string | null>(null);

  const { data, isLoading, isError, refetch } = useQuery<{ items: VendorPurchaseMessageItem[] }>({
    queryKey: ['vendor-purchase-messages'],
    queryFn: async () => {
      const res = await fetch('/api/vendor/purchase-messages');
      const json = (await res.json()) as {
        ok: boolean;
        data?: { items: VendorPurchaseMessageItem[] };
      };
      if (!json.ok) throw new Error('fetch-vendor-messages-failed');
      return json.data!;
    },
    refetchInterval: 30_000,
  });

  const items = data?.items ?? [];

  if (isError) {
    return (
      <ErrorState
        title={t('error_inbox')}
        action={
          <Button variant="secondary" size="sm" onClick={() => refetch()}>
            {t('retry')}
          </Button>
        }
      />
    );
  }
  return (
    <VendorShell variant="dashboard" currentPath="/vendor/messages">
      <div className="mx-auto max-w-2xl px-4 py-6">
        {isLoading && (
          <p className="text-text-muted text-sm" role="status" aria-live="polite" aria-busy="true">
            {t('loading')}
          </p>
        )}

        {!isLoading && items.length === 0 && (
          <p className="text-text-muted text-sm leading-relaxed">{t('empty_inbox')}</p>
        )}

        <Stack gap="2">
          {items.map((item) => {
            const isOpen = expanded === item.orderLineId;
            const buyerLabel = t('buyer_label').replace('{id}', item.orderLineId.slice(0, 8));
            const latestAt = item.latestMessageAt
              ? formatRelative(item.latestMessageAt, locale)
              : null;

            return (
              <div
                key={item.orderLineId}
                className="border-border-default bg-surface-raised rounded-xl border"
              >
                <Button
                  type="button"
                  variant="ghost"
                  className="h-auto w-full justify-start p-0 text-start hover:bg-transparent"
                  onClick={() => setExpanded(isOpen ? null : item.orderLineId)}
                  aria-expanded={isOpen}
                >
                  <div className="flex min-w-0 flex-1 flex-col gap-0.5">
                    <span className="text-text-primary truncate text-sm font-medium">
                      {item.dealTitle}
                    </span>
                    <span className="text-text-muted text-xs">{buyerLabel}</span>
                    {!isOpen && (
                      <span className="text-text-muted mt-0.5 truncate text-xs">
                        {item.latestMessageBody}
                      </span>
                    )}
                  </div>
                  <div className="flex shrink-0 flex-col items-end gap-1">
                    {latestAt && (
                      <span className="text-text-muted text-xs tabular-nums">{latestAt}</span>
                    )}
                    {item.unreadCount > 0 && (
                      <span className="bg-mode-vendor-600 rounded-full px-2 py-0.5 text-xs font-medium text-white">
                        {formatUnreadBadge(item.unreadCount, t)}
                      </span>
                    )}
                  </div>
                </Button>

                {isOpen && (
                  <div className="border-border-default border-t px-4 pb-4">
                    <ThreadPanel purchaseId={item.orderLineId} />
                  </div>
                )}
              </div>
            );
          })}
        </Stack>
      </div>
    </VendorShell>
  );
}

export function VendorPurchaseInbox({ locale }: { locale?: Locale }) {
  return (
    <HydratedIsland locale={locale}>
      <VendorPurchaseInboxInner />
    </HydratedIsland>
  );
}
