'use client';
import { useState } from 'react';
import type { Shift, StoreMember, Position } from '@alqove/api-client';
import { useScheduleMutation } from '@/lib/queries/use-scheduling';
import { Dialog, DialogContent, DialogTitle, DialogDescription } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { instantToLocal, localToInstant } from './schedule-time';
import { scheduleError } from './schedule-feedback';

export function ShiftEditor({ storeId, timezone, date, shift, members, positions, onClose, onReload }: {
  storeId: string; timezone: string; date: string; shift: Shift | null; members: StoreMember[]; positions: Position[];
  onClose: () => void; onReload: () => Promise<unknown>;
}) {
  const [employee, setEmployee] = useState(shift?.store_membership_id ?? '');
  const [position, setPosition] = useState(shift?.position_id ?? '');
  const [start, setStart] = useState(shift ? instantToLocal(shift.starts_at, timezone) : `${date}T09:00`);
  const [end, setEnd] = useState(shift ? instantToLocal(shift.ends_at, timezone) : `${date}T17:00`);
  const [notes, setNotes] = useState(shift?.notes ?? '');
  const [error, setError] = useState('');
  const [confirmDelete, setConfirmDelete] = useState(false);
  const mutation = useScheduleMutation(storeId);
  const stale = /changed|revision|reload before/i.test(error);
  const save = async () => {
    setError('');
    try {
      // Unchanged instants remain byte-for-byte intact, including seconds and
      // folds that were explicitly established elsewhere. Only entered times
      // undergo the strict gap/fold conversion.
      const starts_at = shift && start === instantToLocal(shift.starts_at, timezone) ? shift.starts_at : localToInstant(start, timezone);
      const ends_at = shift && end === instantToLocal(shift.ends_at, timezone) ? shift.ends_at : localToInstant(end, timezone);
      if (new Date(ends_at).getTime() <= new Date(starts_at).getTime()) throw new Error('End must be after start. For overnight shifts, select the next date.');
      const input = { store_membership_id: employee || null, position_id: position || null, starts_at, ends_at, notes: notes || null };
      await mutation.mutateAsync(shift ? { action: 'update', id: shift.id, input: { ...input, revision: shift.revision } } : { action: 'create', input });
      onClose();
    } catch (e) { setError(scheduleError(e)); }
  };
  const remove = async () => {
    if (!shift) return;
    try { await mutation.mutateAsync({ action: 'delete', id: shift.id, revision: shift.revision }); onClose(); }
    catch (e) { setError(scheduleError(e)); }
  };
  const inputClass = 'w-full min-w-0 rounded border bg-transparent p-2';
  return <Dialog open onOpenChange={open => { if (!open && !mutation.isPending) onClose(); }}>
    <DialogContent className="max-h-[90dvh] overflow-y-auto">
      <DialogTitle>{shift ? 'Edit shift' : 'Add shift'}</DialogTitle>
      <DialogDescription>All times use {timezone}. Saving makes this shift a draft; publish the week to share it. Clock-change gaps and ambiguous times must be avoided.</DialogDescription>
      <form className="grid gap-4" onSubmit={e => { e.preventDefault(); void save(); }}>
        <fieldset disabled={mutation.isPending || stale} className="grid gap-4">
          <label className="grid gap-1">Employee<select className={inputClass} value={employee} onChange={e => setEmployee(e.target.value)}><option value="">Open shift</option>
            {employee && !members.some(m => m.id === employee) && <option value={employee}>{shift?.member_name ?? 'Current employee'}</option>}
            {members.filter(m => m.status === 'active').map(m => <option key={m.id} value={m.id}>{m.name}</option>)}</select></label>
          <label className="grid gap-1">Position<select className={inputClass} value={position} onChange={e => setPosition(e.target.value)}><option value="">No position</option>
            {position && !positions.some(p => p.id === position) && <option value={position}>{shift?.position_name ?? 'Current position'}</option>}
            {positions.filter(p => p.is_active).map(p => <option key={p.id} value={p.id}>{p.name}</option>)}</select></label>
          <label className="grid gap-1">Starts (store time)<input required type="datetime-local" className={inputClass} value={start} onChange={e => setStart(e.target.value)} /></label>
          <label className="grid gap-1">Ends (store time)<input required type="datetime-local" className={inputClass} value={end} onChange={e => setEnd(e.target.value)} /></label>
          <label className="grid gap-1">Notes<textarea className={inputClass} maxLength={5000} value={notes} onChange={e => setNotes(e.target.value)} /></label>
        </fieldset>
        {error && <div role="alert" className="space-y-2 text-sm text-red-700"><p>{error}</p><p>Your inputs have not been discarded. Reloading closes this editor.</p><Button type="button" variant="outline" onClick={async () => { const result = await onReload() as { isError?: boolean } | undefined; if (!result?.isError) onClose(); }}>Reload latest schedule</Button></div>}
        {confirmDelete && <p>Delete this shift? This cannot be undone.</p>}
        <div className="flex flex-wrap gap-2">
          <Button type="submit" disabled={mutation.isPending || stale}>{mutation.isPending ? 'Saving…' : 'Save shift'}</Button>
          <Button type="button" variant="outline" disabled={mutation.isPending} onClick={onClose}>Cancel</Button>
          {shift && <Button type="button" variant="destructive" disabled={mutation.isPending || stale} onClick={() => confirmDelete ? void remove() : setConfirmDelete(true)}>{confirmDelete ? 'Confirm delete' : 'Delete shift'}</Button>}
        </div>
      </form>
    </DialogContent>
  </Dialog>;
}
