'use client';

import { useEffect, useState } from 'react';
import { useTranslations } from 'next-intl';
import { Button } from '@/components/ui/shared/Button';
import { Checkbox } from '@/components/ui/shared/Checkbox';
import { Dropdown } from '@/components/ui/shared/Dropdown';
import { FORM_SELECT_CLASS } from '@/components/ui/shared/formSelectStyles';
import { SearchBar } from '@/components/ui/shared/SearchBar';
import { CaseSentLabel } from '@/components/ui/treatment/CaseSentLabel';
import { LabCaseCommentsPanel } from '@/components/ui/lab/LabCaseCommentsPanel';
import { treatmentTypeLabelFromCatalog } from '@/components/ui/treatment/treatmentTypeDisplay';
import { treatmentsApi } from '@/lib/api/treatments';
import { prosthesisCatalogApi } from '@/lib/api/prosthesis-catalog';
import type { ProsthesisCatalogEntry, TreatmentCatalogEntry } from '@/types/treatment-catalog';
import type { LabCaseDraft, LinkedOrganizationOption, TreatmentDetailDraft } from '@/types/treatment';

interface LabCasesDispatchPanelProps {
  details: TreatmentDetailDraft[];
  activeDetailId: string;
  labCases: LabCaseDraft[];
  labDependentCodes: Set<string>;
  treatmentCatalog: TreatmentCatalogEntry[];
  activeLabCaseId: string | null;
  onActiveLabCaseChange: (id: string) => void;
  onLabCasesChange: (labCases: LabCaseDraft[]) => void;
  disabled: boolean;
  canEdit: boolean;
  orgs: LinkedOrganizationOption[];
  organizationSearch: string;
  onOrganizationSearchChange: (value: string) => void;
  recentOrganizationIds: string[];
  onRecentOrganizationPick: (orgId: string) => void;
  sendBusyId: string | null;
  onAddLabCase: () => void;
  onSendLabCase: (labCase: LabCaseDraft) => void;
  onCommentError?: (message: string) => void;
}

function sentDetailClientIds(labCases: LabCaseDraft[]): Set<string> {
  const ids = new Set<string>();
  for (const lc of labCases) {
    if (!lc.sentAt) continue;
    for (const id of lc.detailClientIds) ids.add(id);
  }
  return ids;
}

function detailInOtherDraftShipment(
  detailClientId: string,
  labCases: LabCaseDraft[],
  activeLabCaseClientId: string,
): boolean {
  return labCases.some(
    (lc) =>
      !lc.sentAt &&
      lc.clientId !== activeLabCaseClientId &&
      lc.detailClientIds.includes(detailClientId),
  );
}

function selectableDetailsForDraftShipment(
  details: TreatmentDetailDraft[],
  labCases: LabCaseDraft[],
  labDependentCodes: Set<string>,
  activeLabCase: LabCaseDraft,
): TreatmentDetailDraft[] {
  const sent = sentDetailClientIds(labCases);
  return details.filter((d) => {
    if (!labDependentCodes.has(d.treatmentType)) return false;
    if (sent.has(d.clientId)) return false;
    if (activeLabCase.detailClientIds.includes(d.clientId)) return true;
    return !detailInOtherDraftShipment(d.clientId, labCases, activeLabCase.clientId);
  });
}

function prosthesisTeethRows(
  labCase: LabCaseDraft,
  details: TreatmentDetailDraft[],
  scopeDetailClientId?: string,
): Array<{ detailClientId: string; tooth: string; detailNumber: number }> {
  const rows: Array<{ detailClientId: string; tooth: string; detailNumber: number }> = [];
  for (const clientId of labCase.detailClientIds) {
    if (scopeDetailClientId && clientId !== scopeDetailClientId) continue;
    const detail = details.find((d) => d.clientId === clientId);
    if (!detail || detail.treatmentType !== 'prosthesis') continue;
    const detailNumber = details.findIndex((d) => d.clientId === clientId) + 1;
    for (const tooth of detail.teeth) {
      rows.push({ detailClientId: clientId, tooth, detailNumber });
    }
  }
  return rows;
}

function isProsthesisMapComplete(
  labCase: LabCaseDraft,
  details: TreatmentDetailDraft[],
  scopeDetailClientId?: string,
): boolean {
  const rows = prosthesisTeethRows(labCase, details, scopeDetailClientId);
  if (rows.length === 0) return true;
  return rows.every((row) =>
    labCase.toothProsthesis.some(
      (tp) =>
        tp.detailClientId === row.detailClientId &&
        tp.tooth === row.tooth &&
        Boolean(tp.prosthesisTypeCode),
    ),
  );
}

export function LabCasesDispatchPanel({
  details,
  activeDetailId,
  labCases,
  labDependentCodes,
  treatmentCatalog,
  activeLabCaseId,
  onActiveLabCaseChange,
  onLabCasesChange,
  disabled,
  canEdit,
  orgs,
  organizationSearch,
  onOrganizationSearchChange,
  recentOrganizationIds,
  onRecentOrganizationPick,
  sendBusyId,
  onAddLabCase,
  onSendLabCase,
  onCommentError,
}: LabCasesDispatchPanelProps) {
  const t = useTranslations('treatment');
  const [prosthesisOptions, setProsthesisOptions] = useState<ProsthesisCatalogEntry[]>([]);
  const [applyAllProsthesis, setApplyAllProsthesis] = useState('');

  const activeLinkedOrganizations = orgs.filter((o) => o.active);
  const filteredOrganizations = (() => {
    const q = organizationSearch.trim().toLowerCase();
    if (!q) return activeLinkedOrganizations;
    return activeLinkedOrganizations.filter((o) => o.name.toLowerCase().includes(q));
  })();
  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 && labDependentCodes.has(activeDetail.treatmentType),
  );

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

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

  const detailAlreadyInShipment = Boolean(labCaseForActiveDetail);
  const canAddLabShipment =
    !detailAlreadyInShipment &&
    !detailInOtherDraftShipment(activeDetailId, labCases, '') &&
    !sentDetailClientIds(labCases).has(activeDetailId);

  const sent = Boolean(activeLabCase?.sentAt);

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

  const prosthesisRows = activeLabCase
    ? prosthesisTeethRows(activeLabCase, details, activeDetailId)
    : [];
  const prosthesisComplete = activeLabCase
    ? isProsthesisMapComplete(activeLabCase, details, activeDetailId)
    : true;

  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]);

  // Hide dispatch when the selected treatment detail is not lab-dependent.
  if (!activeDetail || !isLabDependentDetail) {
    return null;
  }

  function detailNumber(d: TreatmentDetailDraft) {
    const idx = details.findIndex((row) => row.clientId === d.clientId);
    return idx >= 0 ? idx + 1 : 0;
  }

  function detailSummary(d: TreatmentDetailDraft) {
    const typeLabel = treatmentTypeLabelFromCatalog(d.treatmentType, treatmentCatalog);
    const teeth = d.teeth.length ? d.teeth.join(', ') : t('teethNone');
    return `${t('detailLabel', { n: detailNumber(d) })} · ${typeLabel} · ${teeth}`;
  }

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

  function setToothProsthesis(
    detailClientId: string,
    tooth: string,
    prosthesisTypeCode: string,
  ) {
    if (!activeLabCase) return;
    const rest = activeLabCase.toothProsthesis.filter(
      (tp) => !(tp.detailClientId === detailClientId && tp.tooth === tooth),
    );
    const next = prosthesisTypeCode
      ? [...rest, { detailClientId, tooth, prosthesisTypeCode }]
      : rest;
    updateActiveLabCase({ toothProsthesis: next });
  }

  function applyProsthesisToAll(code: string) {
    if (!activeLabCase || !code) return;
    const next = prosthesisRows.map((row) => ({
      detailClientId: row.detailClientId,
      tooth: row.tooth,
      prosthesisTypeCode: code,
    }));
    updateActiveLabCase({ toothProsthesis: next });
  }

  function toggleDetailInActiveLabCase(detailClientId: string, checked: boolean) {
    if (!activeLabCase || sent) return;

    onLabCasesChange(
      labCases.map((lc) => {
        if (lc.sentAt) return lc;

        if (lc.clientId === activeLabCase.clientId) {
          const set = new Set(lc.detailClientIds);
          if (checked) set.add(detailClientId);
          else set.delete(detailClientId);

          const keptProsthesis = lc.toothProsthesis.filter((tp) =>
            [...set].includes(tp.detailClientId),
          );

          return { ...lc, detailClientIds: [...set], toothProsthesis: keptProsthesis };
        }

        if (checked) {
          return {
            ...lc,
            detailClientIds: lc.detailClientIds.filter((id) => id !== detailClientId),
          };
        }
        return lc;
      }),
    );
  }

  const includedInActiveShipment = activeLabCase
    ? [activeDetail]
    : [];

  const pickableForActiveDraft =
    activeLabCase && !sent
      ? selectableDetailsForDraftShipment(details, labCases, labDependentCodes, activeLabCase).filter(
          (d) => d.clientId === activeDetailId,
        )
      : [];

  return (
    <div className="surface-card p-4 space-y-4">
      <div className="flex flex-wrap items-center justify-between gap-3">
        <div>
          <h3 className="text-sm font-semibold text-text-primary">{t('labDispatchTitle')}</h3>
          <p className="text-xs text-text-muted mt-0.5">
            {t('labDispatchSubtitle')} {t('labDispatchSendHint')}
          </p>
        </div>
        {canAddLabShipment && (
          <Button
            type="button"
            variant="primary"
            disabled={!canEdit || disabled}
            onClick={onAddLabCase}
          >
            {t('addLabShipment')}
          </Button>
        )}
      </div>

      {!detailAlreadyInShipment ? (
        <p className="text-xs text-text-muted">{t('labDispatchEmpty')}</p>
      ) : activeLabCase ? (
        <div className="space-y-4 border border-border/60 rounded-[var(--radius-md)] p-4 bg-background-secondary/30">
              {sent ? (
                <>
                  <div>
                    <p className="text-xs font-medium text-text-secondary mb-2">
                      {t('labShipmentIncludedDetails')}
                    </p>
                    {includedInActiveShipment.length === 0 ? (
                      <p className="text-xs text-text-muted">{t('labShipmentNoIncludedDetails')}</p>
                    ) : (
                      <ul className="space-y-1.5">
                        {includedInActiveShipment.map((d) => (
                          <li
                            key={d.clientId}
                            className="text-sm text-text-primary rounded-[var(--radius-sm)] border border-border/50 bg-background-secondary/50 px-3 py-2"
                          >
                            {detailSummary(d)}
                          </li>
                        ))}
                      </ul>
                    )}
                  </div>

                  {activeLabCase.id ? (
                    <LabCaseCommentsPanel
                      caseId={activeLabCase.id}
                      canPost={false}
                      canToggleVisibility={false}
                      loadComments={async () => {
                        const r = await treatmentsApi.listLabCaseComments(activeLabCase.id!);
                        return r.data;
                      }}
                      onPost={async () => {
                        throw new Error('Read-only');
                      }}
                      onError={onCommentError}
                    />
                  ) : null}

                  {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}
                  />
                </>
              ) : (
                <>
                  <div>
                    <p className="text-xs font-medium text-text-secondary mb-2">
                      {t('includeDetails')}
                    </p>
                    {pickableForActiveDraft.length === 0 ? (
                      <p className="text-xs text-text-muted">{t('labShipmentNoDetailsAvailable')}</p>
                    ) : (
                      <div className="flex flex-col gap-2">
                        {pickableForActiveDraft.map((d) => {
                          const checked = activeLabCase.detailClientIds.includes(d.clientId);
                          return (
                            <Checkbox
                              key={d.clientId}
                              checked={checked}
                              disabled={disabled}
                              onChange={(next) => toggleDetailInActiveLabCase(d.clientId, next)}
                              label={detailSummary(d)}
                            />
                          );
                        })}
                      </div>
                    )}
                  </div>

                  {activeLabCase.id ? (
                    <LabCaseCommentsPanel
                      caseId={activeLabCase.id}
                      canPost={canEdit && !disabled}
                      canToggleVisibility={false}
                      loadComments={async () => {
                        const r = await treatmentsApi.listLabCaseComments(activeLabCase.id!);
                        return r.data;
                      }}
                      onPost={async (body) => {
                        const r = await treatmentsApi.addLabCaseComment(activeLabCase.id!, { body });
                        return r.data;
                      }}
                      onError={onCommentError}
                    />
                  ) : null}

                  <div className="space-y-2">
                    <p className="text-xs font-medium text-text-secondary">{t('selectLab')}</p>
                    <SearchBar
                      embedded
                      value={organizationSearch}
                      onChange={onOrganizationSearchChange}
                      placeholder={t('searchOrgsPlaceholder')}
                    />
                    {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={() => 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>
                    )}
                    <Dropdown
                      value={activeLabCase.destinationOrganizationId ?? ''}
                      onChange={(e) => {
                        const nextOrgId = e.target.value || null;
                        updateActiveLabCase({
                          destinationOrganizationId: nextOrgId,
                          toothProsthesis: [],
                        });
                        setApplyAllProsthesis('');
                      }}
                      disabled={disabled || filteredOrganizations.length === 0}
                    >
                      <option value="">{t('selectLabPlaceholder')}</option>
                      {filteredOrganizations.map((o) => (
                        <option key={o.id} value={o.id}>
                          {o.name}
                        </option>
                      ))}
                    </Dropdown>
                    {filteredOrganizations.length === 0 && (
                      <p className="text-xs text-text-muted">{t('noOrgMatch')}</p>
                    )}
                  </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>
                      <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>
                      <div className="overflow-x-auto">
                        <table className="w-full text-sm">
                          <thead>
                            <tr className="text-left text-xs text-text-muted">
                              <th className="pb-2 pr-3 font-medium">{t('prosthesisColTooth')}</th>
                              <th className="pb-2 pr-3 font-medium">{t('prosthesisColDetail')}</th>
                              <th className="pb-2 font-medium">{t('prosthesisColType')}</th>
                            </tr>
                          </thead>
                          <tbody>
                            {prosthesisRows.map((row) => {
                              const current =
                                activeLabCase.toothProsthesis.find(
                                  (tp) =>
                                    tp.detailClientId === row.detailClientId &&
                                    tp.tooth === row.tooth,
                                )?.prosthesisTypeCode ?? '';
                              return (
                                <tr key={`${row.detailClientId}-${row.tooth}`} className="border-t border-border/40">
                                  <td className="py-2 pr-3 text-text-primary">{row.tooth}</td>
                                  <td className="py-2 pr-3 text-text-secondary">
                                    {t('detailLabel', { n: row.detailNumber })}
                                  </td>
                                  <td className="py-2">
                                    <select
                                      value={current}
                                      disabled={disabled}
                                      onChange={(e) =>
                                        setToothProsthesis(
                                          row.detailClientId,
                                          row.tooth,
                                          e.target.value,
                                        )
                                      }
                                      className={`${FORM_SELECT_CLASS} w-full min-w-[160px]`}
                                    >
                                      <option value="">{t('prosthesisSelectPlaceholder')}</option>
                                      {prosthesisOptions.map((opt) => (
                                        <option key={opt.code} value={opt.code}>
                                          {opt.label}
                                        </option>
                                      ))}
                                    </select>
                                  </td>
                                </tr>
                              );
                            })}
                          </tbody>
                        </table>
                      </div>
                    </div>
                  ) : null}

                  <div className="flex flex-wrap items-center gap-3 pt-1">
                    <Button
                      type="button"
                      variant="primary"
                      disabled={
                        disabled ||
                        sendBusyId === activeLabCase.clientId ||
                        !activeLabCase.destinationOrganizationId ||
                        activeLabCase.detailClientIds.length === 0 ||
                        !prosthesisComplete
                      }
                      isLoading={sendBusyId === activeLabCase.clientId}
                      onClick={() => onSendLabCase(activeLabCase)}
                    >
                      {t('sendToLab')}
                    </Button>
                  </div>
                </>
              )}
            </div>
      ) : null}
    </div>
  );
}
