/**
 * AppointmentModal — create/edit an appointment (or task) entry.
 * Form validation: React Hook Form + Zod.
 *
 * Pre-fills start_at / end_at when the caller supplies a `prefillDate`
 * (used by clicking an empty day cell in MonthView).
 */

import React, { useEffect, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { Modal } from '@/components/ui/Modal';
import { Button } from '@/components/ui/Button';
import { Input } from '@/components/ui/Input';
import { Select } from '@/components/ui/Select';
import {
  createEntry,
  updateEntry,
  deleteEntry,
  type Calendar,
  type CalendarEntry,
  type EntryCreatePayload,
  type EntryPriority,
  type EntrySubtype,
} from '@/api/calendar';
import { formatDateTimeInput } from '@/utils/date';

export interface AppointmentModalProps {
  open: boolean;
  onClose: () => void;
  /** Existing entry for edit mode. */
  entry?: CalendarEntry | null;
  /** Date used to pre-fill start_at in create mode (defaults to today). */
  prefillDate?: Date | null;
  /** Available calendars (user must pick one for create). */
  calendars: Calendar[];
  /** Active calendar id, used as the default selection. */
  defaultCalendarId?: string | null;
  /** Called after a successful save. */
  onSaved: (entry: CalendarEntry) => void;
  /** Called after a successful delete. */
  onDeleted: (entryId: string) => void;
}

function toDateTimeLocalValue(d: Date | null | undefined): string {
  if (!d) return '';
  return formatDateTimeInput(d);
}

function fromDateTimeLocalValue(v: string): Date | null {
  if (!v) return null;
  const d = new Date(v);
  if (Number.isNaN(d.getTime())) return null;
  return d;
}

// ── Zod Schema ──

const appointmentSchema = z
  .object({
    title: z.string().min(1, 'required'),
    calendar_id: z.string().min(1, 'required'),
    start_at: z.string().min(1, 'required'),
    end_at: z.string().min(1, 'required'),
    all_day: z.boolean().default(false),
    priority: z.enum(['low', 'medium', 'high']).default('medium'),
    subtype: z.enum(['normal', 'follow_up', 'private']).default('normal'),
    location: z.string().optional().default(''),
    description: z.string().optional().default(''),
  })
  .superRefine((data, ctx) => {
    if (data.start_at && data.end_at) {
      const start = new Date(data.start_at);
      const end = new Date(data.end_at);
      if (!Number.isNaN(start.getTime()) && !Number.isNaN(end.getTime())) {
        if (end < start) {
          ctx.addIssue({
            code: z.ZodIssueCode.custom,
            message: 'endBeforeStart',
            path: ['end_at'],
          });
        }
      }
    }
  });

type AppointmentFormData = z.infer<typeof appointmentSchema>;

export function AppointmentModal({
  open,
  onClose,
  entry,
  prefillDate,
  calendars,
  defaultCalendarId,
  onSaved,
  onDeleted,
}: AppointmentModalProps) {
  const { t } = useTranslation();
  const isEdit = !!entry;

  const initialStart = useMemo(() => {
    if (entry?.start_at) return new Date(entry.start_at);
    if (prefillDate) {
      const d = new Date(prefillDate);
      d.setHours(9, 0, 0, 0);
      return d;
    }
    const d = new Date();
    d.setHours(9, 0, 0, 0);
    return d;
  }, [entry, prefillDate]);

  const initialEnd = useMemo(() => {
    if (entry?.end_at) return new Date(entry.end_at);
    const d = new Date(initialStart);
    d.setHours(d.getHours() + 1);
    return d;
  }, [entry, initialStart]);

  const {
    register,
    handleSubmit,
    reset,
    formState: { errors, isSubmitting },
  } = useForm<AppointmentFormData>({
    resolver: zodResolver(appointmentSchema),
    defaultValues: {
      title: '',
      calendar_id: '',
      start_at: toDateTimeLocalValue(initialStart),
      end_at: toDateTimeLocalValue(initialEnd),
      all_day: false,
      priority: 'medium',
      subtype: 'normal',
      location: '',
      description: '',
    },
  });

  // Reset form when entry / prefill / open changes
  useEffect(() => {
    if (!open) return;
    const fallbackId =
      entry?.calendar_id ?? defaultCalendarId ?? calendars[0]?.id ?? '';
    reset({
      title: entry?.title ?? '',
      calendar_id: fallbackId,
      start_at: toDateTimeLocalValue(entry?.start_at ? new Date(entry.start_at) : initialStart),
      end_at: toDateTimeLocalValue(entry?.end_at ? new Date(entry.end_at) : initialEnd),
      all_day: entry?.all_day ?? false,
      priority: entry?.priority ?? 'medium',
      subtype: entry?.subtype ?? 'normal',
      location: entry?.location ?? '',
      description: entry?.description ?? '',
    });
  }, [open, entry, defaultCalendarId, calendars, initialStart, initialEnd, reset]);

  const onSubmit = async (data: AppointmentFormData) => {
    const startDate = fromDateTimeLocalValue(data.start_at);
    const endDate = fromDateTimeLocalValue(data.end_at);
    if (isEdit && entry) {
      const updated = await updateEntry(entry.id, {
        title: data.title,
        description: data.description || null,
        location: data.location || null,
        start_at: startDate ? startDate.toISOString() : null,
        end_at: endDate ? endDate.toISOString() : null,
        all_day: data.all_day,
        priority: data.priority,
        subtype: data.subtype,
        calendar_id: data.calendar_id,
      });
      onSaved(updated);
    } else {
      const payload: EntryCreatePayload = {
        calendar_id: data.calendar_id,
        entry_type: 'appointment',
        title: data.title,
        description: data.description || null,
        location: data.location || null,
        start_at: startDate ? startDate.toISOString() : null,
        end_at: endDate ? endDate.toISOString() : null,
        all_day: data.all_day,
        priority: data.priority,
        subtype: data.subtype,
        status: 'open',
      };
      const created = await createEntry(payload);
      onSaved(created);
    }
    onClose();
  };

  const handleDelete = async () => {
    if (!entry) return;
    if (!window.confirm(t('calendar.deleteEntryConfirm'))) return;
    try {
      await deleteEntry(entry.id);
      onDeleted(entry.id);
      onClose();
    } catch (e) {
      const err = e as { message?: string };
      console.error(err.message ?? t('calendar.errorSave'));
    }
  };

  const calendarOptions = useMemo(
    () => [...calendars.map((c) => ({ value: c.id, label: c.name }))],
    [calendars]
  );

  const errorMsg = (key: string | undefined) => {
    if (!key) return undefined;
    if (key === 'required') return t('validation.required');
    if (key === 'endBeforeStart') return t('calendar.endBeforeStart', 'End must be after start');
    return key;
  };

  return (
    <Modal
      open={open}
      onClose={onClose}
      title={isEdit ? t('calendar.editAppointment') : t('calendar.newAppointment')}
      size="lg"
    >
      <form onSubmit={handleSubmit(onSubmit)} className="space-y-4" data-testid="appointment-modal">
        <div>
          <label className="block text-sm font-medium text-secondary-700 mb-1">
            {t('calendar.appointmentTitle')} *
          </label>
          <Input
            {...register('title')}
            error={errorMsg(errors.title?.message)}
            placeholder={t('calendar.appointmentTitle')}
            data-testid="appointment-title"
          />
        </div>

        <div>
          <label className="block text-sm font-medium text-secondary-700 mb-1">
            {t('calendar.appointmentCalendar')} *
          </label>
          <Select
            {...register('calendar_id')}
            error={errorMsg(errors.calendar_id?.message)}
            options={calendarOptions}
            data-testid="appointment-calendar"
          />
        </div>

        <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
          <div>
            <label className="block text-sm font-medium text-secondary-700 mb-1">
              {t('calendar.appointmentStart')}
            </label>
            <Input
              type="datetime-local"
              {...register('start_at')}
              error={errorMsg(errors.start_at?.message)}
              data-testid="appointment-start"
            />
          </div>
          <div>
            <label className="block text-sm font-medium text-secondary-700 mb-1">
              {t('calendar.appointmentEnd')}
            </label>
            <Input
              type="datetime-local"
              {...register('end_at')}
              error={errorMsg(errors.end_at?.message)}
              data-testid="appointment-end"
            />
          </div>
        </div>

        <div className="flex items-center gap-2">
          <input
            id="appointment-allday"
            type="checkbox"
            {...register('all_day')}
            className="h-4 w-4 rounded border-secondary-300 text-primary-600 focus:ring-primary-500"
            data-testid="appointment-allday"
          />
          <label htmlFor="appointment-allday" className="text-sm text-secondary-700">
            {t('calendar.appointmentAllDay')}
          </label>
        </div>

        <div>
          <label className="block text-sm font-medium text-secondary-700 mb-1">
            {t('calendar.appointmentLocation')}
          </label>
          <Input
            {...register('location')}
            placeholder={t('calendar.appointmentLocation')}
            data-testid="appointment-location"
          />
        </div>

        <div>
          <label className="block text-sm font-medium text-secondary-700 mb-1">
            {t('calendar.appointmentDescription')}
          </label>
          <textarea
            {...register('description')}
            rows={3}
            className="w-full rounded-md border-secondary-300 focus:border-primary-500 focus:ring-primary-500"
            data-testid="appointment-description"
          />
        </div>

        <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
          <div>
            <label className="block text-sm font-medium text-secondary-700 mb-1">
              {t('calendar.appointmentPriority')}
            </label>
            <Select
              {...register('priority')}
              options={[
                { value: 'low', label: t('calendar.priority.low') },
                { value: 'medium', label: t('calendar.priority.medium') },
                { value: 'high', label: t('calendar.priority.high') },
              ]}
              data-testid="appointment-priority"
            />
          </div>
          <div>
            <label className="block text-sm font-medium text-secondary-700 mb-1">
              {t('calendar.appointmentSubtype')}
            </label>
            <Select
              {...register('subtype')}
              options={[
                { value: 'normal', label: t('calendar.subtype.normal') },
                { value: 'follow_up', label: t('calendar.subtype.follow_up') },
                { value: 'private', label: t('calendar.subtype.private') },
              ]}
              data-testid="appointment-subtype"
            />
          </div>
        </div>

        {(errors.title || errors.calendar_id || errors.start_at || errors.end_at) && (
          <div className="text-sm text-danger-700 bg-danger-50 border border-danger-200 rounded-md p-2" data-testid="appointment-error">
            {errorMsg(errors.title?.message) || errorMsg(errors.calendar_id?.message) || errorMsg(errors.start_at?.message) || errorMsg(errors.end_at?.message)}
          </div>
        )}

        <div className="flex justify-between gap-2 pt-2">
          <div>
            {isEdit && (
              <Button
                variant="danger"
                onClick={handleDelete}
                disabled={isSubmitting}
                data-testid="appointment-delete"
                type="button"
              >
                {t('calendar.delete')}
              </Button>
            )}
          </div>
          <div className="flex gap-2">
            <Button variant="ghost" onClick={onClose} disabled={isSubmitting} type="button">
              {t('calendar.cancel')}
            </Button>
            <Button
              variant="primary"
              type="submit"
              isLoading={isSubmitting}
              data-testid="appointment-save"
            >
              {t('calendar.save')}
            </Button>
          </div>
        </div>
      </form>
    </Modal>
  );
}

export default AppointmentModal;
