'use client';

import { useCallback, useEffect, useMemo, useState, type KeyboardEvent } from 'react';
import { useTranslations } from 'next-intl';
import { Eye, EyeOff, Send } from 'lucide-react';
import { getUserFacingError } from '@/components/shared/formatApiError';
import { useAsyncActionById } from '@/lib/hooks/useAsyncAction';
import type { LabCaseComment } from '@/types/cases';

export type LabCaseCommentViewerSide = 'LAB' | 'CLINIC';

interface LabCaseCommentsPanelProps {
  caseId: string;
  viewerSide: LabCaseCommentViewerSide;
  canPost: boolean;
  canToggleVisibility: boolean;
  loadComments: () => Promise<LabCaseComment[]>;
  onPost: (body: string, visibleToClinic?: boolean) => Promise<LabCaseComment>;
  onToggleVisibility?: (commentId: string, visible: boolean) => Promise<LabCaseComment>;
  onError?: (message: string) => void;
  /**
   * Deferred composer: the parent owns the draft value and triggers the post
   * elsewhere (e.g. the "Send to lab" button). No send icon is shown.
   */
  deferSubmit?: boolean;
  composerValue?: string;
  onComposerValueChange?: (value: string) => void;
}

function sortNewestFirst(items: LabCaseComment[]): LabCaseComment[] {
  return [...items].sort(
    (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(),
  );
}

export function LabCaseCommentsPanel({
  caseId,
  viewerSide,
  canPost,
  canToggleVisibility,
  loadComments,
  onPost,
  onToggleVisibility,
  onError,
  deferSubmit = false,
  composerValue,
  onComposerValueChange,
}: LabCaseCommentsPanelProps) {
  const t = useTranslations('caseComments');
  const tErrors = useTranslations('errors');
  const [comments, setComments] = useState<LabCaseComment[]>([]);
  const [loading, setLoading] = useState(false);
  const [posting, setPosting] = useState(false);
  const [body, setBody] = useState('');
  const [visibleToClinic, setVisibleToClinic] = useState(false);
  const toggleBusy = useAsyncActionById();

  const orderedComments = useMemo(() => sortNewestFirst(comments), [comments]);

  const refresh = useCallback(async () => {
    setLoading(true);
    try {
      const items = await loadComments();
      setComments(sortNewestFirst(items));
    } catch (error: unknown) {
      onError?.(getUserFacingError(error, tErrors, t('errorLoad')));
    } finally {
      setLoading(false);
    }
  }, [loadComments, onError, t, tErrors]);

  useEffect(() => {
    void refresh();
  }, [caseId, refresh]);

  async function handlePost() {
    const trimmed = body.trim();
    if (!trimmed || !canPost || posting) return;
    setPosting(true);
    try {
      const created = await onPost(trimmed, visibleToClinic);
      setComments((prev) => sortNewestFirst([created, ...prev]));
      setBody('');
      setVisibleToClinic(false);
    } catch (error: unknown) {
      onError?.(getUserFacingError(error, tErrors, t('errorPost')));
    } finally {
      setPosting(false);
    }
  }

  function handleComposerKeyDown(event: KeyboardEvent<HTMLTextAreaElement>) {
    if (event.key === 'Enter' && !event.shiftKey) {
      event.preventDefault();
      void handlePost();
    }
  }

  async function handleToggle(comment: LabCaseComment) {
    if (!onToggleVisibility || !canToggleVisibility) return;
    await toggleBusy.run(comment.id, async () => {
      try {
        const updated = await onToggleVisibility(comment.id, !comment.visibleToClinic);
        setComments((prev) => prev.map((c) => (c.id === updated.id ? updated : c)));
      } catch (error: unknown) {
        onError?.(getUserFacingError(error, tErrors, t('errorToggle')));
      }
    });
  }

  const composerInputClass =
    'min-w-0 flex-1 h-9 rounded-md border border-border bg-surface px-3 py-1.5 text-sm leading-tight resize-none';

  return (
    <div className="space-y-3 min-w-0">
      <h4 className="text-sm font-medium text-text-primary">{t('title')}</h4>

      {loading ? (
        <p className="text-xs text-text-muted">…</p>
      ) : comments.length === 0 ? (
        <p className="text-xs text-text-muted">{t('empty')}</p>
      ) : (
        <div className="max-h-48 overflow-y-auto overflow-x-hidden rounded-md border border-border bg-background p-2 space-y-2">
          {orderedComments.map((comment) => {
            const mine = comment.authorSide === viewerSide;
            return (
              <div
                key={comment.id}
                className={`flex min-w-0 ${mine ? 'justify-start' : 'justify-end'}`}
              >
                <div
                  className={`max-w-[85%] min-w-0 text-sm break-words ${mine ? 'text-start' : 'text-end'}`}
                >
                  <div
                    className={`flex flex-wrap items-center gap-x-2 gap-y-0.5 text-[11px] text-text-muted ${
                      mine ? 'justify-start' : 'justify-end'
                    }`}
                  >
                    <span className="font-medium text-text-secondary">
                      {comment.authorSide === 'LAB' ? t('labAuthor') : t('clinicAuthor')}
                      {comment.authorName ? ` · ${comment.authorName}` : ''}
                    </span>
                    {comment.showVisibilityStatus !== false ? (
                      comment.visibleToClinic ? (
                        <span className="text-primary">{t('clinicCanSee')}</span>
                      ) : (
                        <span>{t('hiddenFromClinic')}</span>
                      )
                    ) : null}
                    {canToggleVisibility && comment.canToggleVisibility && onToggleVisibility ? (
                      <button
                        type="button"
                        onClick={() => handleToggle(comment)}
                        disabled={toggleBusy.pendingId !== null}
                        className={`shrink-0 p-0.5 rounded hover:bg-border text-text-muted disabled:opacity-40 disabled:cursor-not-allowed ${
                          toggleBusy.pendingId === comment.id ? 'animate-pulse' : ''
                        }`}
                        title={comment.visibleToClinic ? t('makeHidden') : t('makeVisible')}
                        aria-label={comment.visibleToClinic ? t('makeHidden') : t('makeVisible')}
                        aria-busy={toggleBusy.pendingId === comment.id || undefined}
                      >
                        {comment.visibleToClinic ? (
                          <Eye className="h-3.5 w-3.5" />
                        ) : (
                          <EyeOff className="h-3.5 w-3.5" />
                        )}
                      </button>
                    ) : null}
                  </div>
                  <p className="mt-0.5 text-text-primary whitespace-pre-wrap">{comment.body}</p>
                </div>
              </div>
            );
          })}
        </div>
      )}

      {canPost && deferSubmit ? (
        <div className="border-t border-border pt-2">
          <textarea
            value={composerValue ?? ''}
            onChange={(e) => onComposerValueChange?.(e.target.value)}
            placeholder={t('placeholder')}
            rows={1}
            className="w-full h-9 rounded-md border border-border bg-surface px-3 py-1.5 text-sm leading-tight resize-none"
          />
        </div>
      ) : canPost ? (
        <div className="flex items-center gap-2 border-t border-border pt-2 min-w-0">
          <textarea
            value={body}
            onChange={(e) => setBody(e.target.value)}
            onKeyDown={handleComposerKeyDown}
            placeholder={t('placeholder')}
            rows={1}
            className={composerInputClass}
          />
          <div className="flex items-center gap-1 shrink-0">
            {canToggleVisibility ? (
              <button
                type="button"
                onClick={() => setVisibleToClinic((v) => !v)}
                className={`shrink-0 h-9 w-9 inline-flex items-center justify-center rounded-md bg-primary text-white transition-colors hover:opacity-90 ${
                  visibleToClinic ? '' : 'opacity-50'
                }`}
                title={visibleToClinic ? t('composerVisible') : t('composerHidden')}
                aria-label={visibleToClinic ? t('composerVisible') : t('composerHidden')}
                aria-pressed={visibleToClinic}
              >
                {visibleToClinic ? (
                  <Eye className="h-4 w-4 text-white stroke-current" />
                ) : (
                  <EyeOff className="h-4 w-4 text-white stroke-current" />
                )}
              </button>
            ) : null}
            <button
              type="button"
              onClick={() => handlePost()}
              disabled={posting || !body.trim()}
              className="shrink-0 h-9 w-9 inline-flex items-center justify-center rounded-md bg-primary text-white transition-colors hover:opacity-90 disabled:opacity-40 disabled:cursor-not-allowed"
              title={t('send')}
              aria-label={t('send')}
            >
              <Send className="h-4 w-4 text-white stroke-current fill-none rtl:-scale-x-100" />
            </button>
          </div>
        </div>
      ) : null}
    </div>
  );
}
