'use client';

import { useEffect, useId, useState } from 'react';
import { useTranslations } from 'next-intl';
import { Button } from '@/components/ui/shared/Button';
import { DialogCloseButton } from '@/components/ui/shared/DialogCloseButton';
import { ResponsiveDialogOverlay, ResponsiveDialogPanel } from '@/components/ui/shared/ResponsiveDialog';
import { Dropdown } from '@/components/ui/shared/Dropdown';
import { TimeStepInput } from '@/components/ui/shared/TimeStepInput';
import type { AppointmentPurpose, AppointmentRecord } from '@/types/appointment';
import type { TreatmentCatalogEntry } from '@/types/treatment-catalog';
import {
  DROPDOWN_OPTION_BG,
  treatmentTypeColor,
} from '@/components/shared/treatmentTypeDisplay';
import type { Patient } from '@/types/patient';
import { PatientSearchCombobox } from '@/components/ui/patient/PatientSearchCombobox';
import { usePatientSearchQuery } from '@/lib/hooks/usePatientSearchQuery';
import {
  combineLocalDateAndTime,
  compareLocalDayStart,
  formatTimeForInput,
  isSameLocalCalendarDay,
} from '@/components/appointments/appointmentTime';

const DEFAULT_DURATION_MINUTES = 30;

interface AppointmentBookingModalProps {
  open: boolean;
  scheduleDate: Date;
  /** Pre-selected patient from the page sidebar (optional). */
  initialPatient?: Patient;
  onPatientChange?: (patient: Patient | undefined) => void;
  canAddPatient?: boolean;
  onAddPatient?: () => void;
  providerUserId: string | null;
  providerName: string;
  initialStartMinute: number;
  onClose: () => void;
  onSubmit: (payload: {
    patientId: string;
    providerUserId: string;
    startAt: string;
    endAt: string;
    purpose: AppointmentPurpose;
  }) => Promise<void>;
  treatmentCatalog: TreatmentCatalogEntry[];
  editingAppointment?: AppointmentRecord | null;
  loading?: boolean;
  canDelete?: boolean;
  onDelete?: () => void | Promise<void>;
  deleting?: boolean;
}

function patientFromRecord(
  patient: AppointmentRecord['patient'],
): Pick<Patient, 'id' | 'firstName' | 'lastName' | 'mobile'> {
  return {
    id: patient.id,
    firstName: patient.firstName,
    lastName: patient.lastName,
    mobile: patient.mobile,
  };
}

export function AppointmentBookingModal({
  open,
  scheduleDate,
  initialPatient,
  onPatientChange,
  canAddPatient = false,
  onAddPatient,
  providerUserId,
  providerName,
  initialStartMinute,
  onClose,
  onSubmit,
  treatmentCatalog,
  editingAppointment = null,
  loading = false,
  canDelete = false,
  onDelete,
  deleting = false,
}: AppointmentBookingModalProps) {
  const t = useTranslations('appointments');
  const tCommon = useTranslations('common');
  const startInputId = useId();
  const endInputId = useId();

  const defaultPurpose = treatmentCatalog[0]?.code ?? '';

  const [startTime, setStartTime] = useState('09:00');
  const [endTime, setEndTime] = useState('09:30');
  const [purpose, setPurpose] = useState<AppointmentPurpose>(defaultPurpose);
  const [selectedPatient, setSelectedPatient] = useState<
    Pick<Patient, 'id' | 'firstName' | 'lastName' | 'mobile'> | null
  >(null);
  const [error, setError] = useState('');

  const { search, setSearch, patients, loading: loadingPatients } = usePatientSearchQuery(open);

  const patientLocked = Boolean(editingAppointment?.hasTreatment);
  const purposeIndex = treatmentCatalog.findIndex((e) => e.code === purpose);
  const purposeTextColor = treatmentTypeColor(purpose, purposeIndex < 0 ? 0 : purposeIndex);

  useEffect(() => {
    if (!open) {
      return;
    }
    setSearch('');
    if (editingAppointment) {
      const start = new Date(editingAppointment.startAt);
      const end = new Date(editingAppointment.endAt);
      setStartTime(formatTimeForInput(start));
      setEndTime(formatTimeForInput(end));
      setPurpose(editingAppointment.purpose || defaultPurpose);
      setSelectedPatient(patientFromRecord(editingAppointment.patient));
    } else {
      const start = new Date(
        scheduleDate.getFullYear(),
        scheduleDate.getMonth(),
        scheduleDate.getDate(),
        Math.floor(initialStartMinute / 60),
        initialStartMinute % 60,
        0,
        0,
      );
      const endMinute = Math.min(
        initialStartMinute + DEFAULT_DURATION_MINUTES,
        24 * 60 - 1,
      );
      const end = new Date(
        scheduleDate.getFullYear(),
        scheduleDate.getMonth(),
        scheduleDate.getDate(),
        Math.floor(endMinute / 60),
        endMinute % 60,
        0,
        0,
      );
      setStartTime(formatTimeForInput(start));
      setEndTime(formatTimeForInput(end));
      setPurpose(defaultPurpose);
      setSelectedPatient(
        initialPatient
          ? {
              id: initialPatient.id,
              firstName: initialPatient.firstName,
              lastName: initialPatient.lastName,
              mobile: initialPatient.mobile,
            }
          : null,
      );
    }
    setError('');
  }, [
    open,
    scheduleDate,
    initialStartMinute,
    editingAppointment?.id,
    defaultPurpose,
    initialPatient?.id,
    setSearch,
  ]);

  if (!open || !providerUserId) {
    return null;
  }

  function selectPatient(patient: Patient) {
    if (patientLocked) {
      return;
    }
    const next = {
      id: patient.id,
      firstName: patient.firstName,
      lastName: patient.lastName,
      mobile: patient.mobile,
    };
    setSelectedPatient(next);
    onPatientChange?.(patient);
    if (error === t('errorSelectPatient')) {
      setError('');
    }
  }

  async function handleSubmit() {
    setError('');
    if (!providerUserId) {
      return;
    }
    if (!selectedPatient?.id) {
      setError(t('errorSelectPatient'));
      return;
    }

    const startAt = combineLocalDateAndTime(scheduleDate, startTime);
    const endAt = combineLocalDateAndTime(scheduleDate, endTime);

    if (endAt <= startAt) {
      setError(t('errorEndAfterStart'));
      return;
    }

    const now = new Date();
    if (isSameLocalCalendarDay(scheduleDate, now) && startAt.getTime() < now.getTime()) {
      setError(t('errorPastSchedule'));
      return;
    }

    const today = new Date();
    if (compareLocalDayStart(scheduleDate, today) < 0) {
      setError(t('errorPastViewOnly'));
      return;
    }

    await onSubmit({
      patientId: selectedPatient.id,
      providerUserId,
      startAt: startAt.toISOString(),
      endAt: endAt.toISOString(),
      purpose,
    });
  }

  const selectedForDisplay = selectedPatient
    ? ({
        ...selectedPatient,
        isActive: true,
        createdAt: '',
        updatedAt: '',
      } satisfies Patient)
    : null;

  return (
    <ResponsiveDialogOverlay onBackdropClick={onClose} className="bg-black/55">
      <ResponsiveDialogPanel
        maxWidthClass="sm:max-w-md"
        role="dialog"
        aria-modal="true"
        aria-labelledby="appointment-modal-title"
        className="surface-card space-y-4"
      >
        <div className="flex items-start justify-between gap-2">
          <h2 id="appointment-modal-title" className="text-lg font-semibold text-text-primary pr-2">
            {editingAppointment ? t('editTitle') : t('newTitle')}
          </h2>
          <DialogCloseButton onClick={onClose} />
        </div>

        <p className="text-sm text-text-secondary">
          {t('providerLabel')}{' '}
          <span className="text-text-primary font-medium">{providerName}</span>
        </p>

        <div className="space-y-2">
          <label className="block text-sm font-medium text-text-secondary">
            {t('patientLabel')}
          </label>

          <PatientSearchCombobox
            search={search}
            onSearchChange={setSearch}
            patients={patients}
            loading={loadingPatients}
            selectedPatient={selectedForDisplay}
            onSelectPatient={selectPatient}
            showInlineSummary
            readOnly={patientLocked}
            readOnlyHint={patientLocked ? t('patientLockedHint') : undefined}
            canAddPatient={canAddPatient}
            onAddPatient={onAddPatient}
            placeholder={t('patientSearchPlaceholder')}
            emptyResultsMessage={t('patientSearchEmpty')}
            noPermissionMessage={t('noPermissionAdd')}
          />
        </div>

        <div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
          <TimeStepInput
            id={startInputId}
            label={t('startLabel')}
            value={startTime}
            onChange={setStartTime}
          />
          <TimeStepInput
            id={endInputId}
            label={t('endLabel')}
            value={endTime}
            onChange={setEndTime}
          />
        </div>

        <Dropdown
          label={t('purposeLabel')}
          value={purpose}
          onChange={(e) => setPurpose(e.target.value)}
          style={{ color: purposeTextColor }}
        >
          {treatmentCatalog.map((entry, index) => (
            <option
              key={entry.code}
              value={entry.code}
              style={{ color: treatmentTypeColor(entry.code, index), backgroundColor: DROPDOWN_OPTION_BG }}
            >
              {entry.label}
            </option>
          ))}
        </Dropdown>

        {error && <p className="text-sm text-red-400">{error}</p>}

        {editingAppointment?.hasTreatment ? (
          <p className="text-sm text-text-secondary">{t('deleteBlockedHint')}</p>
        ) : null}

        <div className="flex flex-col-reverse gap-2 sm:flex-row sm:flex-wrap sm:items-center sm:justify-between">
          {editingAppointment && canDelete && onDelete ? (
            <Button
              type="button"
              variant="danger"
              onClick={() => void onDelete()}
              disabled={loading || deleting}
              isLoading={deleting}
              fullWidth
              className="sm:w-auto"
            >
              {tCommon('delete')}
            </Button>
          ) : null}
          <div className="flex flex-col-reverse sm:flex-row gap-2 sm:ml-auto w-full sm:w-auto">
            <Button
              type="button"
              variant="ghost"
              onClick={onClose}
              disabled={loading || deleting}
              fullWidth
              className="sm:w-auto"
            >
              {tCommon('cancel')}
            </Button>
            <Button
              type="button"
              variant="primary"
              onClick={() => void handleSubmit()}
              isLoading={loading}
              disabled={deleting}
              fullWidth
              className="sm:w-auto"
            >
              {tCommon('save')}
            </Button>
          </div>
        </div>
      </ResponsiveDialogPanel>
    </ResponsiveDialogOverlay>
  );
}
