'use client';

import { useEffect, useRef, useState } from 'react';
import { useTranslations } from 'next-intl';
import { Button } from '@/components/ui/shared/Button';
import { Checkbox } from '@/components/ui/shared/Checkbox';
import { ConnectedSelectionBadge } from '@/components/ui/treatment/ConnectedSelectionBadge';
import { isDetailReadyForLabDispatch, isLabCaseCompleted } from '@/components/treatment/treatmentDetailRules';
import { AppDateInput } from '@/components/ui/shared/AppDateInput';
import { toDateInputValue } from '@/components/lab/labCaseDueDateDisplay';
import { FORM_SELECT_CLASS } from '@/components/shared/formSelectStyles';
import { LinkedOrganizationSearchCombobox } from '@/components/ui/treatment/LinkedOrganizationSearchCombobox';
import { CaseSentLabel } from '@/components/ui/treatment/CaseSentLabel';
import { DetailLabCaseCommentsSection } from '@/components/ui/treatment/DetailLabCaseCommentsSection';
import { LabCaseTrackerCard } from '@/components/ui/treatment/LabCaseTrackerCard';
import { treatmentTypeLabelFromCatalog } from '@/components/shared/treatmentTypeDisplay';
import { treatmentsApi } from '@/lib/api/treatments';
import { prosthesisCatalogApi } from '@/lib/api/prosthesis-catalog';
import {
  lastProsthesisTypeForLab,
  loadLabDispatchDefaults,
  rememberLastLab,
  rememberLastProsthesisType,
} from '@/components/treatment/labDispatchDefaults';
import type { ProsthesisCatalogEntry, TreatmentCatalogEntry } from '@/types/treatment-catalog';
import type { LabCaseDraft, LinkedOrganizationOption, TreatmentDetailDraft } from '@/types/treatment';
import type { PatientLabCaseSummary } from '@/types/lab-case-activity';
import { getUserFacingError } from '@/components/shared/formatApiError';
import { groupsFromFlatTeeth } from '@/components/treatment/toothSelectionGroups';

interface LabCasesDispatchPanelProps {
  details: TreatmentDetailDraft[];
  activeDetailId: string;
  labCases: LabCaseDraft[];
  labDependentCodes: Set<string>;
  treatmentCatalog: TreatmentCatalogEntry[];
  clinicOrganizationId?: string | null;
  labCaseSummary?: PatientLabCaseSummary | null;
  locale: string;
  onLabCaseSummaryChange?: (summary: PatientLabCaseSummary) => void;
  onLabCaseMarkedRead?: (labCaseId: string) => void;
  onLabCaseActivityChange?: () => void;
  activeLabCaseId: string | null;
  onLabCasesChange: (labCases: LabCaseDraft[]) => void;
  disabled: boolean;
  canEdit: boolean;
  orgs: LinkedOrganizationOption[];
  organizationSearch: string;
  onOrganizationSearchChange: (value: string) => void;
  recentOrganizationIds: string[];
  onRecentOrganizationPick: (orgId: string) => void;
  canInviteLab?: boolean;
  onInviteLab?: () => void;
  sendBusyId: string | null;
  onSendLabCase: (labCase: LabCaseDraft, comment?: string) => void | Promise<void>;
  onCommentError?: (message: string) => void;
}

type ProsthesisGroupRow = {
  groupId: string;
  kind: 'connected' | 'single';
  teeth: string[];
  detailClientId: string;
  detailNumber: number;
};

function prosthesisGroupRows(
  labCase: LabCaseDraft,
  activeDetail: TreatmentDetailDraft,
  detailNumber: number,
): ProsthesisGroupRow[] {
  if (labCase.detailClientId !== activeDetail.clientId) return [];
  if (activeDetail.treatmentType !== 'prosthesis') return [];

  const groups =
    activeDetail.toothSelectionGroups.length > 0
      ? activeDetail.toothSelectionGroups
      : groupsFromFlatTeeth(activeDetail.teeth);

  return groups.map((g) => ({
    groupId: g.groupId,
    kind: g.kind,
    teeth: g.teeth,
    detailClientId: activeDetail.clientId,
    detailNumber,
  }));
}

function isProsthesisMapComplete(
  labCase: LabCaseDraft,
  rows: ProsthesisGroupRow[],
): boolean {
  if (rows.length === 0) return true;
  return rows.every((row) =>
    row.teeth.every((tooth) =>
      labCase.toothProsthesis.some(
        (tp) =>
          tp.detailClientId === row.detailClientId &&
          tp.tooth === tooth &&
          tp.selectionGroupId === row.groupId &&
          Boolean(tp.prosthesisTypeCode),
      ),
    ),
  );
}

function toothProsthesisForRows(
  rows: ProsthesisGroupRow[],
  prosthesisTypeCode: string,
): LabCaseDraft['toothProsthesis'] {
  return rows.flatMap((row) =>
    row.teeth.map((tooth) => ({
      detailClientId: row.detailClientId,
      tooth,
      prosthesisTypeCode,
      selectionGroupId: row.groupId,
    })),
  );
}

export function LabCasesDispatchPanel({
  details,
  activeDetailId,
  labCases,
  labDependentCodes,
  treatmentCatalog,
  clinicOrganizationId,
  labCaseSummary,
  locale,
  onLabCaseSummaryChange,
  onLabCaseMarkedRead,
  onLabCaseActivityChange,
  activeLabCaseId,
  onLabCasesChange,
  disabled,
  canEdit,
  orgs,
  organizationSearch,
  onOrganizationSearchChange,
  recentOrganizationIds,
  onRecentOrganizationPick,
  canInviteLab = false,
  onInviteLab,
  sendBusyId,
  onSendLabCase,
  onCommentError,
}: LabCasesDispatchPanelProps) {
  const t = useTranslations('treatment');
  const tErrors = useTranslations('errors');
  const [prosthesisOptions, setProsthesisOptions] = useState<ProsthesisCatalogEntry[]>([]);
  const [applyAllProsthesis, setApplyAllProsthesis] = useState('');
  const [pendingComment, setPendingComment] = useState('');
  const autoFilledCaseRef = useRef<string | null>(null);
  const hasTrackerSummary = Boolean(labCaseSummary && labCaseSummary.labCaseId);

  const activeLinkedOrganizations = orgs.filter((o) => o.active);
  const recentOrganizations = recentOrganizationIds
    .map((id) => activeLinkedOrganizations.find((o) => o.id === id))
    .filter(Boolean) as LinkedOrganizationOption[];

  const activeDetail = details.find((d) => d.clientId === activeDetailId) ?? null;
  const isLabDependentDetail = Boolean(
    activeDetail && isDetailReadyForLabDispatch(activeDetail, labDependentCodes),
  );

  const labCaseForActiveDetail =
    labCases.find((lc) => lc.detailClientId === activeDetailId) ?? null;

  const activeLabCase =
    labCaseForActiveDetail ??
    (activeLabCaseId ? labCases.find((lc) => lc.clientId === activeLabCaseId) : null);

  const sent = Boolean(activeLabCase?.sentAt);
  const activeDetailNumber = details.findIndex((d) => d.clientId === activeDetailId) + 1;

  const activeLabOrgName = activeLabCase?.destinationOrganizationId
    ? orgs.find((o) => o.id === activeLabCase.destinationOrganizationId)?.name
    : null;

  const prosthesisRows = activeLabCase && activeDetail
    ? prosthesisGroupRows(activeLabCase, activeDetail, activeDetailNumber)
    : [];
  const prosthesisComplete = activeLabCase
    ? isProsthesisMapComplete(activeLabCase, prosthesisRows)
    : true;
  const flatToothCount = prosthesisRows.reduce((sum, row) => sum + row.teeth.length, 0);

  useEffect(() => {
    if (!activeLabCase?.destinationOrganizationId) {
      setProsthesisOptions([]);
      return;
    }

    let cancelled = false;
    void prosthesisCatalogApi
      .list(activeLabCase.destinationOrganizationId)
      .then((res) => {
        if (!cancelled) setProsthesisOptions(res.data);
      })
      .catch(() => {
        if (!cancelled) setProsthesisOptions([]);
      });

    return () => {
      cancelled = true;
    };
  }, [activeLabCase?.destinationOrganizationId]);

  useEffect(() => {
    setPendingComment('');
  }, [activeLabCase?.clientId]);

  function updateActiveLabCase(patch: Partial<LabCaseDraft>) {
    if (!activeLabCase) return;
    onLabCasesChange(
      labCases.map((lc) => (lc.clientId === activeLabCase.clientId ? { ...lc, ...patch } : lc)),
    );
  }

  useEffect(() => {
    if (!activeLabCase || sent || !activeDetail) return;
    const ids = activeDetail.attachmentMetas.map((a) => a.id);
    const missing = ids.filter((id) => !activeLabCase.attachmentIds.includes(id));
    if (missing.length === 0) return;
    updateActiveLabCase({ attachmentIds: [...activeLabCase.attachmentIds, ...missing] });
    // eslint-disable-next-line react-hooks/exhaustive-deps -- only sync newly uploaded files
  }, [activeDetail?.attachmentMetas, activeLabCase?.clientId, sent]);

  useEffect(() => {
    if (!activeLabCase || sent || activeLabCase.destinationOrganizationId) return;
    const lastLabId = loadLabDispatchDefaults(clinicOrganizationId).lastLabId;
    const lastLab = lastLabId
      ? activeLinkedOrganizations.find((o) => o.id === lastLabId)
      : undefined;
    if (!lastLab) return;
    updateActiveLabCase({ destinationOrganizationId: lastLab.id, toothProsthesis: [] });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [activeLabCase?.clientId, clinicOrganizationId, sent]);

  useEffect(() => {
    if (!activeLabCase || sent) return;
    if (!activeLabCase.destinationOrganizationId) return;
    if (prosthesisOptions.length === 0 || prosthesisRows.length === 0) return;
    const fillKey = `${activeLabCase.clientId}:${prosthesisRows.length}`;
    if (autoFilledCaseRef.current === fillKey) return;
    if (isProsthesisMapComplete(activeLabCase, prosthesisRows)) {
      autoFilledCaseRef.current = fillKey;
      return;
    }
    const lastCode = lastProsthesisTypeForLab(
      clinicOrganizationId,
      activeLabCase.destinationOrganizationId,
    );
    if (!lastCode || !prosthesisOptions.some((opt) => opt.code === lastCode)) return;
    autoFilledCaseRef.current = fillKey;
    setApplyAllProsthesis(lastCode);
    updateActiveLabCase({ toothProsthesis: toothProsthesisForRows(prosthesisRows, lastCode) });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [
    activeLabCase?.clientId,
    activeLabCase?.destinationOrganizationId,
    clinicOrganizationId,
    prosthesisOptions,
    prosthesisRows.length,
    sent,
  ]);

  if (!activeDetail || !isLabDependentDetail) {
    return null;
  }

  function setGroupProsthesis(row: ProsthesisGroupRow, prosthesisTypeCode: string) {
    if (!activeLabCase) return;
    const toothSet = new Set(row.teeth);
    const rest = activeLabCase.toothProsthesis.filter(
      (tp) => !(tp.detailClientId === row.detailClientId && toothSet.has(tp.tooth)),
    );
    const next = prosthesisTypeCode
      ? [
          ...rest,
          ...row.teeth.map((tooth) => ({
            detailClientId: row.detailClientId,
            tooth,
            prosthesisTypeCode,
            selectionGroupId: row.groupId,
          })),
        ]
      : rest;
    updateActiveLabCase({ toothProsthesis: next });
    if (prosthesisTypeCode && activeLabCase.destinationOrganizationId) {
      rememberLastProsthesisType(
        clinicOrganizationId,
        activeLabCase.destinationOrganizationId,
        prosthesisTypeCode,
      );
    }
  }

  function applyProsthesisToAll(code: string) {
    if (!activeLabCase || !code) return;
    updateActiveLabCase({ toothProsthesis: toothProsthesisForRows(prosthesisRows, code) });
    if (activeLabCase.destinationOrganizationId) {
      rememberLastProsthesisType(
        clinicOrganizationId,
        activeLabCase.destinationOrganizationId,
        code,
      );
    }
  }

  function toggleAttachmentInActiveLabCase(attachmentId: string, checked: boolean) {
    if (!activeLabCase || sent) return;
    const set = new Set(activeLabCase.attachmentIds);
    if (checked) set.add(attachmentId);
    else set.delete(attachmentId);
    updateActiveLabCase({ attachmentIds: [...set] });
  }

  function handleSelectOrganization(org: LinkedOrganizationOption) {
    autoFilledCaseRef.current = null;
    updateActiveLabCase({
      destinationOrganizationId: org.id,
      toothProsthesis: [],
    });
    setApplyAllProsthesis('');
    rememberLastLab(clinicOrganizationId, org.id);
  }

  const caseFullyComplete = isLabCaseCompleted(activeLabCase?.taskProgress);
  const canEditDueDate = canEdit && !disabled && (!sent || !caseFullyComplete);
  const canPostComments = canEdit && !caseFullyComplete;
  const canShowComments = Boolean(activeLabCase?.id);
  const commentsDeferSubmit = Boolean(!sent);

  async function handleSentDueDateBlur(nextValue: string) {
    if (!activeLabCase?.id || !sent || !canEditDueDate) return;
    const dueDate = nextValue || null;
    if (dueDate === (activeLabCase.dueDate?.slice(0, 10) ?? null)) return;
    try {
      const response = await treatmentsApi.updateLabCaseDueDate(activeLabCase.id, dueDate);
      updateActiveLabCase({
        dueDate: response.data.dueDate,
        taskProgress: response.data.taskProgress ?? activeLabCase.taskProgress,
      });
    } catch (error) {
      onCommentError?.(getUserFacingError(error, tErrors, t('dueDateUpdateError')));
    }
  }

  function renderDueDateField() {
    if (!activeLabCase) return null;
    const inputValue = toDateInputValue(activeLabCase.dueDate);
    const dueDateInputId = `lab-case-due-date-${activeLabCase.clientId}`;

    return (
      <div className="w-full min-w-0 sm:w-auto sm:shrink-0 sm:text-end">
        <div className="flex flex-wrap items-center gap-2 sm:justify-end">
          <label
            htmlFor={dueDateInputId}
            className="text-xs font-medium text-text-secondary shrink-0"
          >
            {t('dueDateLabel')}{' '}
            <span className="font-normal text-text-muted">({t('dueDateOptional')})</span>
          </label>
          <AppDateInput
            id={dueDateInputId}
            value={inputValue}
            disabled={!canEditDueDate}
            onChange={(next) => {
              updateActiveLabCase({ dueDate: next || null });
            }}
            onBlur={(committed) => {
              if (sent) void handleSentDueDateBlur(committed);
            }}
            className={`${FORM_SELECT_CLASS} w-full min-w-0 max-w-full sm:max-w-[11rem] rounded-md py-1.5 text-sm`}
          />
        </div>
        {sent && caseFullyComplete && activeLabCase.dueDate ? (
          <p className="mt-1.5 text-[11px] text-text-muted sm:text-end">{t('dueDateLockedCompleted')}</p>
        ) : null}
      </div>
    );
  }

  const typeLabel = treatmentTypeLabelFromCatalog(activeDetail.treatmentType, treatmentCatalog);
  const teethLabel = activeDetail.teeth.length ? [...activeDetail.teeth].sort().join(', ') : t('teethNone');
  const activeDetailAttachments = activeDetail.attachmentMetas ?? [];

  return (
    <div className="surface-card p-3 sm:p-4 space-y-4 min-w-0 overflow-x-hidden">
      <div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
        <div className="min-w-0">
          <h3 className="text-sm font-semibold text-text-primary">{t('labDispatchTitle')}</h3>
          <p className="text-xs text-text-muted mt-0.5">
            {typeLabel} · {teethLabel}
          </p>
        </div>
        {activeLabCase ? renderDueDateField() : null}
      </div>

      {activeLabCase ? (
        <div className="space-y-4 border border-border/60 rounded-[var(--radius-md)] p-3 sm:p-4 bg-background-secondary/30 min-w-0">
          {sent ? (
            <>
              {activeLabOrgName ? (
                <div>
                  <p className="text-xs font-medium text-text-secondary">{t('selectLab')}</p>
                  <p className="text-sm text-text-primary mt-1">{activeLabOrgName}</p>
                </div>
              ) : null}

              <CaseSentLabel
                treatmentCase={{
                  destinationOrganizationId: activeLabCase.destinationOrganizationId,
                  sendToOrganizationIds: activeLabCase.destinationOrganizationId
                    ? [activeLabCase.destinationOrganizationId]
                    : [],
                  sentAt: activeLabCase.sentAt ?? null,
                  sends: activeLabCase.sends,
                }}
                orgs={orgs}
              />

              {hasTrackerSummary && labCaseSummary ? (
                <LabCaseTrackerCard
                  summary={labCaseSummary}
                  locale={locale}
                  onSummaryChange={onLabCaseSummaryChange}
                  onMarkedRead={onLabCaseMarkedRead}
                />
              ) : null}

              {canShowComments && activeLabCase?.id ? (
                <DetailLabCaseCommentsSection
                  labCaseId={activeLabCase.id}
                  canPost={canPostComments}
                  onError={onCommentError}
                  onMarkRead={onLabCaseMarkedRead}
                  onActivityChange={onLabCaseActivityChange}
                />
              ) : null}
            </>
          ) : (
            <>
              <div className="space-y-2">
                <p className="text-xs font-medium text-text-secondary">{t('selectLab')}</p>
                <LinkedOrganizationSearchCombobox
                  search={organizationSearch}
                  onSearchChange={onOrganizationSearchChange}
                  organizations={activeLinkedOrganizations}
                  selectedOrganizationId={activeLabCase.destinationOrganizationId}
                  onSelectOrganization={handleSelectOrganization}
                  disabled={disabled}
                  canInviteLab={canInviteLab}
                  onInviteLab={onInviteLab}
                  noPermissionMessage={t('noOrgInvitePermission')}
                />
                {recentOrganizations.length > 0 && (
                  <div className="flex flex-wrap items-center gap-2">
                    <span className="text-xs text-text-muted">{t('recent')}</span>
                    {recentOrganizations.map((o) => (
                      <button
                        key={o.id}
                        type="button"
                        disabled={disabled}
                        onClick={() => {
                          handleSelectOrganization(o);
                          onRecentOrganizationPick(o.id);
                        }}
                        className="text-xs rounded-[var(--radius-sm)] border border-border/70 px-2 py-1 text-text-secondary hover:text-text-primary hover:border-border focus:outline-none focus-visible:ring-2 focus-visible:ring-primary/35 disabled:opacity-50"
                      >
                        {o.name}
                      </button>
                    ))}
                  </div>
                )}
              </div>

              {prosthesisRows.length > 0 && activeLabCase.destinationOrganizationId ? (
                <div className="space-y-3 border-t border-border/60 pt-3">
                  <p className="text-xs font-medium text-text-secondary">
                    {t('prosthesisTypesTitle')}
                  </p>
                  {flatToothCount > 1 ? (
                    <label className="block text-xs text-text-muted space-y-1">
                      {t('prosthesisApplyAll')}
                      <select
                        value={applyAllProsthesis}
                        disabled={disabled || prosthesisOptions.length === 0}
                        onChange={(e) => {
                          const code = e.target.value;
                          setApplyAllProsthesis(code);
                          if (code) applyProsthesisToAll(code);
                        }}
                        className={`${FORM_SELECT_CLASS} w-full mt-1`}
                      >
                        <option value="">{t('prosthesisSelectPlaceholder')}</option>
                        {prosthesisOptions.map((opt) => (
                          <option key={opt.code} value={opt.code}>
                            {opt.label}
                          </option>
                        ))}
                      </select>
                    </label>
                  ) : null}
                  <div className="space-y-3">
                    {prosthesisRows.map((row) => {
                      const current =
                        activeLabCase.toothProsthesis.find(
                          (tp) =>
                            tp.detailClientId === row.detailClientId &&
                            tp.selectionGroupId === row.groupId &&
                            row.teeth.includes(tp.tooth),
                        )?.prosthesisTypeCode ??
                        activeLabCase.toothProsthesis.find(
                          (tp) =>
                            tp.detailClientId === row.detailClientId &&
                            row.teeth.includes(tp.tooth),
                        )?.prosthesisTypeCode ??
                        '';
                      return (
                        <label
                          key={row.groupId}
                          className="block text-xs text-text-muted rounded-[var(--radius-sm)] border border-border/50 bg-background-secondary/40 px-3 py-2 min-w-0"
                        >
                          <span className="grid grid-cols-1 gap-2 md:grid-cols-2 md:items-center md:gap-3">
                            <span className="flex flex-wrap items-center gap-2 text-text-secondary min-w-0 break-words">
                              {row.kind === 'connected' ? <ConnectedSelectionBadge /> : null}
                              <span className="min-w-0">
                                {row.kind === 'connected'
                                  ? t('prosthesisConnectedLabel')
                                  : t('prosthesisColTooth')}
                                {': '}
                                <span className="text-text-primary">{row.teeth.join(', ')}</span>
                              </span>
                            </span>
                            <select
                              value={current}
                              disabled={disabled}
                              onChange={(e) => setGroupProsthesis(row, e.target.value)}
                              className={`${FORM_SELECT_CLASS} w-full min-w-0`}
                              aria-label={
                                row.kind === 'connected'
                                  ? t('prosthesisConnectedLabel')
                                  : t('prosthesisColType')
                              }
                            >
                              <option value="">{t('prosthesisSelectPlaceholder')}</option>
                              {prosthesisOptions.map((opt) => (
                                <option key={opt.code} value={opt.code}>
                                  {opt.label}
                                </option>
                              ))}
                            </select>
                          </span>
                        </label>
                      );
                    })}
                  </div>
                </div>
              ) : null}

              {activeDetailAttachments.length > 0 ? (
                <div>
                  <p className="text-xs font-medium text-text-secondary mb-1">
                    {t('labShipmentAttachments')}
                  </p>
                  <p className="text-[11px] text-text-muted mb-2">{t('labShipmentAttachmentsHint')}</p>
                  <div className="flex flex-col gap-2">
                    {activeDetailAttachments.map((att) => (
                      <Checkbox
                        key={att.id}
                        checked={activeLabCase.attachmentIds.includes(att.id)}
                        disabled={disabled}
                        onChange={(next) => toggleAttachmentInActiveLabCase(att.id, next)}
                        label={`${att.fileName} (${(att.sizeBytes / 1024).toFixed(1)} KB)`}
                      />
                    ))}
                  </div>
                </div>
              ) : null}

              {hasTrackerSummary && labCaseSummary ? (
                <LabCaseTrackerCard
                  summary={labCaseSummary}
                  locale={locale}
                  onSummaryChange={onLabCaseSummaryChange}
                  onMarkedRead={onLabCaseMarkedRead}
                />
              ) : null}

              {canShowComments && activeLabCase?.id ? (
                <DetailLabCaseCommentsSection
                  labCaseId={activeLabCase.id}
                  canPost={canPostComments}
                  deferSubmit={commentsDeferSubmit}
                  composerValue={pendingComment}
                  onComposerValueChange={setPendingComment}
                  onError={onCommentError}
                  onMarkRead={onLabCaseMarkedRead}
                  onActivityChange={onLabCaseActivityChange}
                />
              ) : null}

              <div className="flex flex-wrap items-center gap-3 pt-1">
                <Button
                  type="button"
                  variant="primary"
                  className="w-full sm:w-auto"
                  disabled={
                    disabled ||
                    sendBusyId === activeLabCase.clientId ||
                    !activeLabCase.destinationOrganizationId ||
                    !activeLabCase.detailClientId ||
                    !prosthesisComplete
                  }
                  isLoading={sendBusyId === activeLabCase.clientId}
                  onClick={() => {
                    if (activeLabCase.destinationOrganizationId) {
                      rememberLastLab(clinicOrganizationId, activeLabCase.destinationOrganizationId);
                      const codes = [
                        ...new Set(
                          activeLabCase.toothProsthesis
                            .map((tp) => tp.prosthesisTypeCode)
                            .filter(Boolean),
                        ),
                      ];
                      if (codes.length === 1) {
                        rememberLastProsthesisType(
                          clinicOrganizationId,
                          activeLabCase.destinationOrganizationId,
                          codes[0],
                        );
                      }
                    }
                    return onSendLabCase(activeLabCase, pendingComment.trim());
                  }}
                >
                  {t('sendToLab')}
                </Button>
              </div>
            </>
          )}
        </div>
      ) : null}
    </div>
  );
}
