/**
 * CustomerCaseDetail — full case view for the customer.
 * Shows timeline, offers (with decide controls), message thread.
 */

'use client';

import { useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import { useT, useLocale } from '@/lib/i18n/react';
import { formatDateTime, formatRelative } from '@/lib/format';
import type { StringBundle } from '@/lib/i18n/types';
import { cn } from '@/lib/cn';
import { CaseDetailSkeleton, SkeletonGuard } from '@/components/ui/feedback/Skeleton';
import { ErrorState } from '@/components/ui/feedback/ErrorState';
import { CaseStatusTimeline } from '@/components/ui/domain/support/CaseStatusTimeline';
import { CaseOfferCard } from '@/components/ui/domain/support/CaseOfferCard';
import { RefundActionDialog } from '@/components/ui/domain/support/RefundActionDialog';
import { InlineNotice } from '@/components/ui/feedback/InlineNotice';
import { Badge } from '@/components/ui/primitives/Badge';
import { Button } from '@/components/ui/primitives/Button';
import { FormField } from '@/components/ui/primitives/FormField';
import { Textarea } from '@/components/ui/primitives/Textarea';
import { useDecideOffer, usePostMessage } from './useCaseMutations';
import { qk } from '@/lib/query/keys';
import { ErrorBoundary } from '@/components/ui/feedback/ErrorBoundary';
import { HydratedIsland } from '@/components/HydratedIsland';
import { Icon } from '@/components/ui/icons/Icon';
import { getCaseStatusTone } from './caseStatusTone';
import type {
  CaseSummaryView,
  CaseOfferView,
  SupportMessageView,
  StateTransitionView,
  MessageAuthorType,
} from '@/server/support/types';
import type { NoticeTone } from '@/components/ui/feedback/InlineNotice';

interface CaseDetailData {
  case: CaseSummaryView;
  offers: CaseOfferView[];
  messages: SupportMessageView[];
  transitions: StateTransitionView[];
}

async function fetchCase(caseId: string): Promise<CaseDetailData> {
  const res = await fetch(`/api/cases/${caseId}`);
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json() as Promise<CaseDetailData>;
}

function messageAuthorLabel(
  authorType: MessageAuthorType,
  tDetail: StringBundle['cases']['detail'],
): string {
  if (authorType === 'customer') return tDetail.author_me;
  if (authorType === 'vendor') return tDetail.author_vendor;
  return tDetail.author_support;
}

export interface CustomerCaseDetailProps {
  caseId: string;
  /** When true, show a one-time "case opened" success notice (set after redirect from /cases/new). */
  justOpened?: boolean;
}

export function CustomerCaseDetail(props: CustomerCaseDetailProps) {
  return (
    <HydratedIsland>
      <CustomerCaseDetailInner {...props} />
    </HydratedIsland>
  );
}

function CustomerCaseDetailInner({ caseId, justOpened = false }: CustomerCaseDetailProps) {
  const t = useT('cases');
  const tCommon = useT('common');
  const { locale } = useLocale();
  const tDetail = t('detail') as unknown as StringBundle['cases']['detail'];
  const tOpen = t('open') as unknown as StringBundle['cases']['open'];
  const tCategories = t('categories') as unknown as StringBundle['cases']['categories'];
  const tStatus = t('status') as unknown as StringBundle['cases']['status'];

  const { data, isLoading, isError, refetch } = useQuery({
    queryKey: qk.case(caseId),
    queryFn: () => fetchCase(caseId),
  });

  const decideMut = useDecideOffer();
  const messageMut = usePostMessage();

  const [pendingDecision, setPendingDecision] = useState<{
    offerId: string;
    outcome: CaseOfferView['outcome'];
    amountCents: number | null;
  } | null>(null);
  const [messageText, setMessageText] = useState('');

  if (isLoading && !data)
    return (
      <div aria-busy="true" role="status">
        <SkeletonGuard delay={0}>
          <CaseDetailSkeleton />
        </SkeletonGuard>
      </div>
    );
  if (isError) {
    return (
      <ErrorState
        title={tDetail.error_title}
        description={tDetail.error_description}
        action={
          <div className="flex flex-col items-center gap-2">
            <Button variant="secondary" size="sm" onClick={() => refetch()}>
              {tCommon('retry')}
            </Button>
            <a
              href="/cases"
              className="text-brand-primary-700 hover:text-brand-primary-900 text-sm font-semibold underline"
            >
              {tDetail.back_to_cases}
            </a>
          </div>
        }
      />
    );
  }
  if (!data) return null;

  const { case: c, offers, messages, transitions } = data;

  const pendingOffer = offers.find((o) => o.status === 'pending');
  const canDecide = c.status === 'vendor_offered' && !!pendingOffer;
  const isResolved = c.status === 'resolved' || c.status === 'closed';

  const resolvedBanner = isResolved
    ? (() => {
        const resolvedOffer = offers.find(
          (o) => o.status === 'accepted' || o.status === 'auto_executed',
        );
        if (
          resolvedOffer &&
          (resolvedOffer.outcome === 'refund_full' || resolvedOffer.outcome === 'refund_partial')
        ) {
          return { title: tDetail.resolved_banner_refund, tone: 'success' as NoticeTone };
        }
        if (resolvedOffer && resolvedOffer.outcome === 'replacement') {
          return { title: tDetail.resolved_banner_replacement, tone: 'success' as NoticeTone };
        }
        return { title: tDetail.resolved_banner_no_refund, tone: 'info' as NoticeTone };
      })()
    : null;

  async function confirmDecide() {
    if (!pendingDecision) return;
    await decideMut.mutateAsync({
      caseId,
      offerId: pendingDecision.offerId,
      decision: 'accept',
    });
    setPendingDecision(null);
  }

  async function rejectOffer() {
    if (!pendingOffer) return;
    await decideMut.mutateAsync({ caseId, offerId: pendingOffer.id, decision: 'reject' });
  }

  async function sendMessage(e: React.SyntheticEvent<HTMLFormElement>) {
    e.preventDefault();
    if (!messageText.trim()) return;
    await messageMut.mutateAsync({ caseId, text: messageText.trim() });
    setMessageText('');
  }

  const statusLabel = tStatus[c.status as keyof StringBundle['cases']['status']] ?? c.status;

  return (
    <ErrorBoundary>
      <article className="space-y-6">
        <a
          href="/cases"
          className="text-brand-primary-700 hover:text-brand-primary-900 inline-flex items-center gap-1 text-sm font-semibold underline"
        >
          <Icon name="ChevronRight" size="sm" className="shrink-0" mirror aria-hidden />
          {tDetail.back_to_cases}
        </a>

        <header>
          <h1 className="text-text-primary text-xl font-bold">
            {tCategories[c.category as keyof StringBundle['cases']['categories']] ?? c.category}
          </h1>
          <Badge tone={getCaseStatusTone(c.status)} size="sm" className="mt-2">
            {statusLabel}
          </Badge>
        </header>

        {justOpened && !isResolved && (
          <InlineNotice
            tone="success"
            title={tDetail.opened_notice_title}
            description={tDetail.opened_notice_description}
          />
        )}

        {resolvedBanner && <InlineNotice tone={resolvedBanner.tone} title={resolvedBanner.title} />}

        {/* Offers */}
        {offers.length > 0 && (
          <section aria-label={tDetail.offers_section_label} className="space-y-3">
            {offers.map((offer) => (
              <CaseOfferCard
                key={offer.id}
                offer={offer}
                canDecide={canDecide && offer.id === pendingOffer?.id}
                onDecide={(decision) => {
                  if (decision === 'accept') {
                    setPendingDecision({
                      offerId: offer.id,
                      outcome: offer.outcome,
                      amountCents: offer.amountCents,
                    });
                  } else {
                    rejectOffer();
                  }
                }}
              />
            ))}
          </section>
        )}

        {/* Timeline */}
        <CaseStatusTimeline transitions={transitions} />

        {/* Message thread */}
        {messages.length > 0 && (
          <section aria-label={tDetail.thread_title} className="space-y-3">
            <h2 className="text-text-secondary text-sm font-semibold">{tDetail.thread_title}</h2>
            <ul className="space-y-2">
              {messages.map((m) => {
                const isOwn = m.authorType === 'customer';
                return (
                  <li
                    key={m.id}
                    className={cn(
                      'flex max-w-[85%] flex-col gap-1 rounded-lg p-3 text-sm',
                      isOwn
                        ? 'bg-brand-primary-50 self-start'
                        : 'border-border bg-surface-base self-end border',
                    )}
                  >
                    <div className="flex items-center justify-between gap-2">
                      <Badge tone="neutral" size="sm">
                        {messageAuthorLabel(m.authorType, tDetail)}
                      </Badge>
                      <time
                        className="text-text-muted text-xs"
                        dateTime={m.createdAt}
                        title={formatDateTime(m.createdAt, locale)}
                      >
                        {formatRelative(m.createdAt, locale)}
                      </time>
                    </div>
                    <p className="text-text-primary">{m.body}</p>
                  </li>
                );
              })}
            </ul>
          </section>
        )}

        {/* New message */}
        {!isResolved && (
          <form onSubmit={sendMessage} className="space-y-2">
            <FormField label={tDetail.new_message_label}>
              <Textarea
                name="message"
                rows={3}
                value={messageText}
                onChange={(e) => setMessageText(e.target.value)}
              />
            </FormField>
            <Button type="submit" variant="secondary" size="sm" disabled={messageMut.isPending}>
              {messageMut.isPending ? tOpen.submitting : tDetail.send_message}
            </Button>
          </form>
        )}

        {/* Confirm accept dialog */}
        {pendingDecision && (
          <RefundActionDialog
            open
            outcome={pendingDecision.outcome}
            amountCents={pendingDecision.amountCents}
            onConfirm={confirmDecide}
            onCancel={() => setPendingDecision(null)}
            processing={decideMut.isPending}
          />
        )}
      </article>
    </ErrorBoundary>
  );
}
