'use client';

import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useTranslations } from 'next-intl';
import { Trash2 } from 'lucide-react';
import { getUserFacingError } from '@/components/shared/formatApiError';
import { FORM_SELECT_CLASS } from '@/components/shared/formSelectStyles';
import { prosthesisTypeColorFromCatalog } from '@/components/treatment/prosthesisTypeDisplay';
import {
  applyShiftRange,
  deriveTeethFromGroups,
  groupsFromFlatTeeth,
  linkedEdgesFromGroups,
  linkAdjacentTeeth,
  normalizeToothSelectionGroups,
  pruneToothProsthesisForGroups,
  toggleToothInGroups,
  toothEdgeKey,
  unlinkAdjacentTeeth,
  type ToothSelectionGroup,
} from '@/components/treatment/toothSelectionGroups';
import { AppDateInput } from '@/components/ui/shared/AppDateInput';
import { Button } from '@/components/ui/shared/Button';
import { ConnectedSelectionBadge } from '@/components/ui/treatment/ConnectedSelectionBadge';
import { FdiToothChart } from '@/components/ui/treatment/FdiToothChart';
import { toDateInputValue } from '@/components/lab/labCaseDueDateDisplay';
import { casesApi } from '@/lib/api/cases';
import { prosthesisCatalogApi } from '@/lib/api/prosthesis-catalog';
import type { LabCaseAttachmentMeta, LabCaseDetail } from '@/types/cases';
import type { FdiToothId } from '@/types/treatment';
import type { LinkedOrganizationOption } from '@/types/treatment';
import type { ProsthesisCatalogEntry } from '@/types/treatment-catalog';

const INPUT_CLASS =
  'mt-1 w-full rounded-[var(--radius-md)] border border-border bg-background-secondary/90 text-text-primary text-sm px-3 py-2 placeholder:text-text-muted focus:outline-none focus:ring-2 focus:ring-primary/35';

type LineDraft = {
  clientId: string;
  id?: string;
  teeth: FdiToothId[];
  toothSelectionGroups: ToothSelectionGroup[];
  comment: string;
  toothProsthesis: Array<{
    tooth: string;
    prosthesisTypeCode: string;
    selectionGroupId?: string;
    detailClientId: string;
  }>;
  attachments: LabCaseAttachmentMeta[];
};

function newLine(): LineDraft {
  const clientId =
    typeof crypto !== 'undefined' && 'randomUUID' in crypto
      ? crypto.randomUUID()
      : `line-${Date.now()}`;
  return {
    clientId,
    teeth: [],
    toothSelectionGroups: [],
    comment: '',
    toothProsthesis: [],
    attachments: [],
  };
}

function linesFromDetail(labCase: LabCaseDetail): LineDraft[] {
  const source = labCase.lines ?? [];
  if (source.length === 0) return [newLine()];
  return source.map((line) => {
    const groups = normalizeToothSelectionGroups(line.toothSelectionGroups);
    const teeth = (line.teeth as FdiToothId[]) ?? [];
    return {
      clientId: line.clientId || line.id,
      id: line.id,
      teeth,
      toothSelectionGroups: groups.length ? groups : groupsFromFlatTeeth(teeth),
      comment: line.comment ?? '',
      toothProsthesis: labCase.toothProsthesis
        .filter((tp) => tp.lineId === line.id)
        .map((tp) => ({
          tooth: tp.tooth,
          prosthesisTypeCode: tp.prosthesisTypeCode,
          selectionGroupId: tp.selectionGroupId,
          detailClientId: line.clientId || line.id,
        })),
      attachments: labCase.attachments.filter(
        (a) => a.detailClientKey === (line.clientId || line.id),
      ),
    };
  });
}

interface CaseCreatePanelProps {
  labCase: LabCaseDetail;
  canEdit: boolean;
  onSaved: (detail: LabCaseDetail) => void;
  onStarted: (detail: LabCaseDetail) => void;
  onDeleted: () => void;
  onError: (message: string) => void;
}

export function CaseCreatePanel({
  labCase,
  canEdit,
  onSaved,
  onStarted,
  onDeleted,
  onError,
}: CaseCreatePanelProps) {
  const t = useTranslations('cases');
  const tTreatment = useTranslations('treatment');
  const tErrors = useTranslations('errors');
  const tCommon = useTranslations('common');

  const [referringClinicName, setReferringClinicName] = useState(
    labCase.referringClinicName ?? '',
  );
  const [referringDentistName, setReferringDentistName] = useState(
    labCase.referringDentistName ?? '',
  );
  const [patientDisplayName, setPatientDisplayName] = useState(
    labCase.patientDisplayName ?? '',
  );
  const [patientDisplayMobile, setPatientDisplayMobile] = useState(
    labCase.patientDisplayMobile ?? '',
  );
  const [partnerClinicOrganizationId, setPartnerClinicOrganizationId] = useState(
    labCase.partnerClinicOrganizationId ?? '',
  );
  const [dueDate, setDueDate] = useState(toDateInputValue(labCase.dueDate));
  const [lines, setLines] = useState<LineDraft[]>(() => linesFromDetail(labCase));
  const [activeLineId, setActiveLineId] = useState(
    () => linesFromDetail(labCase)[0]?.clientId ?? '',
  );
  const [partners, setPartners] = useState<LinkedOrganizationOption[]>([]);
  const [prosthesisOptions, setProsthesisOptions] = useState<ProsthesisCatalogEntry[]>([]);
  const [applyAllProsthesis, setApplyAllProsthesis] = useState('');
  const [saving, setSaving] = useState(false);
  const [starting, setStarting] = useState(false);
  const [deleting, setDeleting] = useState(false);
  const [uploadBusy, setUploadBusy] = useState(false);
  const rangeAnchorRef = useRef<FdiToothId | null>(null);
  const hydratedIdRef = useRef(labCase.id);
  const skipSaveRef = useRef(true);
  const startingRef = useRef(false);
  const deletingRef = useRef(false);
  const allowPersistWhileStartingRef = useRef(false);
  const attachmentInputRef = useRef<HTMLInputElement>(null);

  useEffect(() => {
    if (hydratedIdRef.current === labCase.id) return;
    hydratedIdRef.current = labCase.id;
    skipSaveRef.current = true;
    const nextLines = linesFromDetail(labCase);
    setReferringClinicName(labCase.referringClinicName ?? '');
    setReferringDentistName(labCase.referringDentistName ?? '');
    setPatientDisplayName(labCase.patientDisplayName ?? '');
    setPatientDisplayMobile(labCase.patientDisplayMobile ?? '');
    setPartnerClinicOrganizationId(labCase.partnerClinicOrganizationId ?? '');
    setDueDate(toDateInputValue(labCase.dueDate));
    setLines(nextLines);
    setActiveLineId(nextLines[0]?.clientId ?? '');
  }, [labCase]);

  useEffect(() => {
    void casesApi.listLinkedClinics().then((r) => setPartners(r.data)).catch(() => undefined);
    void prosthesisCatalogApi.list().then((r) => setProsthesisOptions(r.data)).catch(() => undefined);
  }, []);

  const activeLine = lines.find((l) => l.clientId === activeLineId) ?? lines[0];
  const groups =
    activeLine?.toothSelectionGroups.length
      ? activeLine.toothSelectionGroups
      : groupsFromFlatTeeth(activeLine?.teeth ?? []);
  const selected = new Set(activeLine?.teeth ?? []);
  const linkedEdges = linkedEdgesFromGroups(groups);

  const prosthesisRows = groups.map((g) => ({
    groupId: g.groupId,
    kind: g.kind,
    teeth: g.teeth,
  }));

  const toothColors = useMemo(() => {
    const colors: Partial<Record<FdiToothId, string>> = {};
    for (const tp of activeLine?.toothProsthesis ?? []) {
      const color = prosthesisTypeColorFromCatalog(tp.prosthesisTypeCode, prosthesisOptions);
      if (color) colors[tp.tooth as FdiToothId] = color;
    }
    return colors;
  }, [activeLine?.toothProsthesis, prosthesisOptions]);

  const buildPayload = useCallback(
    () => ({
      referringClinicName: referringClinicName.trim() || null,
      referringDentistName: referringDentistName.trim() || null,
      patientDisplayName: patientDisplayName.trim() || null,
      patientDisplayMobile: patientDisplayMobile.trim() || null,
      partnerClinicOrganizationId: partnerClinicOrganizationId || null,
      dueDate: dueDate || null,
      lines: lines.map((line) => ({
        clientId: line.clientId,
        id: line.id,
        teeth: line.teeth,
        toothSelectionGroups: line.toothSelectionGroups,
        comment: line.comment,
        toothProsthesis: line.toothProsthesis.map((tp) => ({
          tooth: tp.tooth,
          prosthesisTypeCode: tp.prosthesisTypeCode,
          selectionGroupId: tp.selectionGroupId,
        })),
        attachmentIds: line.attachments.map((a) => a.id),
      })),
    }),
    [
      referringClinicName,
      referringDentistName,
      patientDisplayName,
      patientDisplayMobile,
      partnerClinicOrganizationId,
      dueDate,
      lines,
    ],
  );

  const persist = useCallback(async () => {
    if (deletingRef.current) {
      return null;
    }
    if (startingRef.current && !allowPersistWhileStartingRef.current) {
      return null;
    }
    setSaving(true);
    try {
      const response = await casesApi.update(labCase.id, buildPayload());
      setLines((prev) =>
        prev.map((line) => {
          const saved = response.data.lines?.find((l) => l.clientId === line.clientId);
          return saved ? { ...line, id: saved.id } : line;
        }),
      );
      onSaved(response.data);
      return response.data;
    } catch (error: unknown) {
      onError(getUserFacingError(error, tErrors, t('errorSaveCase')));
      return null;
    } finally {
      setSaving(false);
    }
  }, [buildPayload, labCase.id, onError, onSaved, t, tErrors]);

  const persistRef = useRef(persist);
  persistRef.current = persist;

  useEffect(() => {
    if (skipSaveRef.current) {
      skipSaveRef.current = false;
      return;
    }
    if (!canEdit || startingRef.current || deletingRef.current) return;
    const timeout = setTimeout(() => {
      void persistRef.current();
    }, 500);
    return () => clearTimeout(timeout);
  }, [buildPayload, canEdit]);

  function updateActiveLine(patch: (line: LineDraft) => LineDraft) {
    setLines((prev) =>
      prev.map((line) => (line.clientId === activeLine?.clientId ? patch(line) : line)),
    );
  }

  async function handleDelete() {
    if (!canEdit) return;
    if (!window.confirm(t('confirmDeleteDraftCase'))) return;
    deletingRef.current = true;
    skipSaveRef.current = true;
    setDeleting(true);
    try {
      await casesApi.deleteDraft(labCase.id);
      onDeleted();
    } catch (error: unknown) {
      deletingRef.current = false;
      setDeleting(false);
      onError(getUserFacingError(error, tErrors, t('errorDeleteCase')));
    }
  }

  async function handleStart() {
    if (!canEdit) return;
    setStarting(true);
    startingRef.current = true;
    skipSaveRef.current = true;
    allowPersistWhileStartingRef.current = true;
    try {
      const saved = await persist();
      allowPersistWhileStartingRef.current = false;
      if (!saved) {
        startingRef.current = false;
        return;
      }
      skipSaveRef.current = true;
      const response = await casesApi.start(labCase.id);
      onStarted(response.data);
    } catch (error: unknown) {
      startingRef.current = false;
      onError(getUserFacingError(error, tErrors, t('errorStartCase')));
    } finally {
      allowPersistWhileStartingRef.current = false;
      setStarting(false);
    }
  }

  async function handleUpload(files: FileList | null) {
    if (!files?.length || !activeLine || !canEdit) return;
    setUploadBusy(true);
    try {
      await persist();
      const response = await casesApi.uploadLineAttachments(
        labCase.id,
        activeLine.clientId,
        Array.from(files),
      );
      updateActiveLine((line) => ({
        ...line,
        attachments: [...line.attachments, ...response.data],
      }));
    } catch (error: unknown) {
      onError(getUserFacingError(error, tErrors, t('errorSaveCase')));
    } finally {
      setUploadBusy(false);
      if (attachmentInputRef.current) attachmentInputRef.current.value = '';
    }
  }

  const disabled = !canEdit || starting || deleting;

  return (
    <div className="space-y-4">
      <div className="flex flex-wrap items-start justify-between gap-3">
        <div>
          <h2 className="text-lg font-semibold text-text-primary">{t('addCaseTitle')}</h2>
          <p className="text-sm text-text-muted mt-0.5">{t('addCaseSubtitle')}</p>
        </div>
        <div className="flex flex-wrap items-center gap-2">
          <Button
            type="button"
            variant="danger"
            disabled={disabled || saving}
            onClick={() => handleDelete()}
          >
            {tCommon('delete')}
          </Button>
          <Button
            type="button"
            variant="primary"
            disabled={disabled || saving}
            onClick={() => void handleStart()}
          >
            {starting ? tCommon('loading') : t('startCase')}
          </Button>
        </div>
      </div>

      <div className="grid gap-3 sm:grid-cols-2">
        <label className="text-xs font-medium text-text-muted">
          {t('referringClinic')}
          <input
            className={INPUT_CLASS}
            value={referringClinicName}
            disabled={disabled}
            onChange={(e) => setReferringClinicName(e.target.value)}
          />
        </label>
        <label className="text-xs font-medium text-text-muted">
          {t('referringDentist')}
          <input
            className={INPUT_CLASS}
            value={referringDentistName}
            disabled={disabled}
            onChange={(e) => setReferringDentistName(e.target.value)}
          />
        </label>
        <label className="text-xs font-medium text-text-muted">
          {t('patientName')}
          <input
            className={INPUT_CLASS}
            value={patientDisplayName}
            disabled={disabled}
            onChange={(e) => setPatientDisplayName(e.target.value)}
          />
        </label>
        <label className="text-xs font-medium text-text-muted">
          {t('patientMobile')}
          <input
            className={INPUT_CLASS}
            value={patientDisplayMobile}
            disabled={disabled}
            onChange={(e) => setPatientDisplayMobile(e.target.value)}
          />
        </label>
        <label className="text-xs font-medium text-text-muted">
          {t('partnerClinic')}
          <select
            className={`${FORM_SELECT_CLASS} ${INPUT_CLASS} mt-1`}
            value={partnerClinicOrganizationId}
            disabled={disabled}
            onChange={(e) => setPartnerClinicOrganizationId(e.target.value)}
          >
            <option value="">{t('partnerClinicNone')}</option>
            {partners.map((org) => (
              <option key={org.id} value={org.id}>
                {org.name}
              </option>
            ))}
          </select>
        </label>
        <label className="text-xs font-medium text-text-muted">
          {t('dueDateField')}
          <AppDateInput
            value={dueDate}
            onChange={setDueDate}
            disabled={disabled}
            className={`${INPUT_CLASS} mt-1`}
          />
        </label>
      </div>

      <div className="flex flex-wrap items-center justify-between gap-2">
        <p className="text-sm font-semibold text-text-primary">{t('caseLinesTitle')}</p>
        <Button
          type="button"
          variant="primary"
          disabled={disabled}
          onClick={() => {
            const line = newLine();
            setLines((prev) => [...prev, line]);
            setActiveLineId(line.clientId);
          }}
        >
          {t('addLine')}
        </Button>
      </div>

      <div className="flex flex-wrap gap-2">
        {lines.map((line, idx) => {
          const isActive = line.clientId === activeLine?.clientId;
          return (
            <div
              key={line.clientId}
              className={`inline-flex items-stretch overflow-hidden rounded-[var(--radius-md)] border ${
                isActive
                  ? 'border-primary bg-primary-soft'
                  : 'border-border/70 hover:border-border'
              }`}
            >
              <button
                type="button"
                className="px-3 py-1.5 text-sm text-text-primary"
                onClick={() => setActiveLineId(line.clientId)}
              >
                {t('lineChip', { n: idx + 1 })}
              </button>
              {lines.length > 1 ? (
                <button
                  type="button"
                  disabled={disabled}
                  title={tCommon('delete')}
                  aria-label={t('removeLineAria', { n: idx + 1 })}
                  onClick={() => {
                    setLines((prev) => {
                      const next = prev.filter((l) => l.clientId !== line.clientId);
                      if (activeLineId === line.clientId) {
                        setActiveLineId(next[0]?.clientId ?? '');
                      }
                      return next;
                    });
                  }}
                  className="inline-flex items-center border-s border-border/60 px-1.5 text-text-muted hover:bg-red-500/15 hover:text-red-600"
                >
                  <Trash2 className="h-3.5 w-3.5" aria-hidden />
                </button>
              ) : null}
            </div>
          );
        })}
      </div>

      {activeLine ? (
        <>
          <FdiToothChart
            selected={selected}
            linkedEdges={linkedEdges}
            toothColors={toothColors}
            disabled={disabled}
            onToggle={(fdi, event) => {
              if (disabled) return;
              const currentGroups =
                activeLine.toothSelectionGroups.length > 0
                  ? activeLine.toothSelectionGroups
                  : groupsFromFlatTeeth(activeLine.teeth);
              let nextGroups: ToothSelectionGroup[] | null = null;
              if (event.shiftKey) {
                const anchor = rangeAnchorRef.current;
                if (!anchor || anchor === fdi) {
                  rangeAnchorRef.current = fdi;
                  return;
                }
                nextGroups = applyShiftRange(currentGroups, anchor, fdi);
                rangeAnchorRef.current = fdi;
              } else {
                nextGroups = toggleToothInGroups(currentGroups, fdi);
                rangeAnchorRef.current = fdi;
              }
              if (!nextGroups) return;
              updateActiveLine((line) => ({
                ...line,
                toothSelectionGroups: nextGroups!,
                teeth: deriveTeethFromGroups(nextGroups!),
                toothProsthesis: pruneToothProsthesisForGroups(
                  line.toothProsthesis,
                  line.clientId,
                  nextGroups!,
                ),
              }));
            }}
            onToggleLink={(a, b) => {
              if (disabled) return;
              const currentGroups =
                activeLine.toothSelectionGroups.length > 0
                  ? activeLine.toothSelectionGroups
                  : groupsFromFlatTeeth(activeLine.teeth);
              const edgeLinked = linkedEdgesFromGroups(currentGroups).has(toothEdgeKey(a, b));
              const nextGroups = edgeLinked
                ? unlinkAdjacentTeeth(currentGroups, a, b)
                : linkAdjacentTeeth(currentGroups, a, b);
              if (!nextGroups) return;
              updateActiveLine((line) => ({
                ...line,
                toothSelectionGroups: nextGroups,
                teeth: deriveTeethFromGroups(nextGroups),
                toothProsthesis: pruneToothProsthesisForGroups(
                  line.toothProsthesis,
                  line.clientId,
                  nextGroups,
                ),
              }));
            }}
          />

          {prosthesisRows.length > 0 ? (
            <div className="space-y-3">
              <p className="text-xs font-medium text-text-secondary">
                {tTreatment('prosthesisTypesTitle')}
              </p>
              {prosthesisRows.every((r) => r.kind === 'single') &&
              prosthesisRows.reduce((sum, r) => sum + r.teeth.length, 0) > 1 ? (
                <label className="block text-xs text-text-muted space-y-1">
                  {tTreatment('prosthesisApplyAll')}
                  <select
                    value={applyAllProsthesis}
                    disabled={disabled || prosthesisOptions.length === 0}
                    onChange={(e) => {
                      const code = e.target.value;
                      setApplyAllProsthesis(code);
                      if (!code) return;
                      updateActiveLine((line) => ({
                        ...line,
                        toothProsthesis: prosthesisRows.flatMap((row) =>
                          row.teeth.map((tooth) => ({
                            tooth,
                            prosthesisTypeCode: code,
                            selectionGroupId: row.groupId,
                            detailClientId: line.clientId,
                          })),
                        ),
                      }));
                    }}
                    className={`${FORM_SELECT_CLASS} w-full mt-1`}
                  >
                    <option value="">{tTreatment('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 =
                    activeLine.toothProsthesis.find(
                      (tp) =>
                        tp.selectionGroupId === row.groupId &&
                        (row.teeth as string[]).includes(tp.tooth),
                    )?.prosthesisTypeCode ??
                    activeLine.toothProsthesis.find((tp) =>
                      (row.teeth as string[]).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"
                    >
                      <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">
                          {row.kind === 'connected' ? <ConnectedSelectionBadge /> : null}
                          <span>
                            {row.kind === 'connected'
                              ? tTreatment('prosthesisConnectedLabel')
                              : tTreatment('prosthesisColTooth')}
                            {': '}
                            <span className="text-text-primary">{row.teeth.join(', ')}</span>
                          </span>
                        </span>
                        <select
                          value={current}
                          disabled={disabled}
                          onChange={(e) => {
                            const code = e.target.value;
                            updateActiveLine((line) => {
                              const rest = line.toothProsthesis.filter(
                                (tp) => !(row.teeth as string[]).includes(tp.tooth),
                              );
                              const next = code
                                ? row.teeth.map((tooth) => ({
                                    tooth,
                                    prosthesisTypeCode: code,
                                    selectionGroupId: row.groupId,
                                    detailClientId: line.clientId,
                                  }))
                                : [];
                              return { ...line, toothProsthesis: [...rest, ...next] };
                            });
                          }}
                          className={`${FORM_SELECT_CLASS} w-full min-w-0`}
                        >
                          <option value="">{tTreatment('prosthesisSelectPlaceholder')}</option>
                          {prosthesisOptions.map((opt) => (
                            <option key={opt.code} value={opt.code}>
                              {opt.label}
                            </option>
                          ))}
                        </select>
                      </span>
                    </label>
                  );
                })}
              </div>
            </div>
          ) : null}

          <label className="block text-xs font-medium text-text-muted">
            {tTreatment('comments')}
            <textarea
              className={`${INPUT_CLASS} resize-y min-h-[60px]`}
              value={activeLine.comment}
              disabled={disabled}
              onChange={(e) =>
                updateActiveLine((line) => ({ ...line, comment: e.target.value }))
              }
            />
          </label>

          <div className="space-y-2">
            <div className="flex items-center justify-between gap-2">
              <p className="text-xs font-medium text-text-muted">{tTreatment('attachments')}</p>
              <Button
                type="button"
                variant="outline"
                size="sm"
                disabled={disabled || uploadBusy}
                onClick={() => attachmentInputRef.current?.click()}
              >
                {tTreatment('chooseFiles')}
              </Button>
              <input
                ref={attachmentInputRef}
                type="file"
                multiple
                className="hidden"
                onChange={(e) => void handleUpload(e.target.files)}
              />
            </div>
            {activeLine.attachments.length ? (
              <ul className="text-xs text-text-secondary space-y-1">
                {activeLine.attachments.map((file) => (
                  <li key={file.id}>{file.fileName}</li>
                ))}
              </ul>
            ) : (
              <p className="text-xs text-text-muted">{t('noAttachments')}</p>
            )}
          </div>
        </>
      ) : null}
    </div>
  );
}
