'use client';

import { useCallback, useEffect, 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 { toothJobRowsForDetail } from '@/components/treatment/prosthesisTree';
import { LabCaseToothJobsList } from '@/components/ui/lab/LabCaseProsthesisGroupsList';
import {
  deriveTeethFromGroups,
  groupsFromFlatTeeth,
  linkedEdgesFromGroups,
  linkAdjacentTeeth,
  normalizeToothSelectionGroups,
  pruneToothProsthesisForGroups,
  toothEdgeKey,
  unlinkAdjacentTeeth,
  type ToothSelectionGroup,
} from '@/components/treatment/toothSelectionGroups';
import { AppDateInput } from '@/components/ui/shared/AppDateInput';
import { Button } from '@/components/ui/shared/Button';
import { ProsthesisAssignChart } from '@/components/ui/treatment/ProsthesisAssignChart';
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 [saving, setSaving] = useState(false);
  const [starting, setStarting] = useState(false);
  const [deleting, setDeleting] = useState(false);
  const [uploadBusy, setUploadBusy] = useState(false);
  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 toothJobRows = activeLine
    ? toothJobRowsForDetail(activeLine.toothProsthesis, activeLine.clientId)
    : [];

  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 ? (
        <>
          <ProsthesisAssignChart
            groups={groups}
            toothProsthesis={activeLine.toothProsthesis}
            detailClientId={activeLine.clientId}
            catalog={prosthesisOptions}
            disabled={disabled}
            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,
                ),
              }));
            }}
            onChange={({ groups: nextGroups, toothProsthesis }) => {
              updateActiveLine((line) => ({
                ...line,
                toothSelectionGroups: nextGroups,
                teeth: deriveTeethFromGroups(nextGroups),
                toothProsthesis,
              }));
            }}
          />

          <div className="space-y-2">
            <p className="text-xs font-medium text-text-secondary">
              {tTreatment('prosthesisTypesTitle')}
            </p>
            <p className="text-[11px] text-text-muted">{tTreatment('prosthesisEditOnChart')}</p>
            {toothJobRows.length === 0 ? (
              <p className="text-xs text-amber-700">{tTreatment('prosthesisMissingOnChart')}</p>
            ) : (
              <LabCaseToothJobsList
                rows={toothJobRows}
                prosthesisCatalog={prosthesisOptions}
              />
            )}
          </div>

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