'use client'

import { useState, useEffect, useMemo } from'react'
import { createClient } from'@/lib/supabase/client'
import SupplierPicker, { type SupplierPickerValue } from'@/components/intake/supplier-picker'
import { deriveSupplierPatch } from'@/lib/planning/supplier-patch'
import type { Consultant, AppointmentType, PlanningProject, Assignment, WorkMode, AssignmentStatus } from'@/lib/planning-types'

interface Props {
 assignment: Assignment
 consultants: Consultant[]
 appointmentTypes: AppointmentType[]
 planningProjects: PlanningProject[]
 onClose: () => void
 onSaved: () => void
 onDeleted: () => void
 /** FB-36 (P0 compliance, composition profile): work_mode ("Arbeitsort") capture on/off. */
 workModeCapture: boolean
}

const cls ='w-full h-8 rounded border border-muted text-[13px] text-foreground px-2 bg-card focus:outline-none focus:border-primary focus:ring-1 focus:ring-primary'
const lbl ='block text-[12px] font-medium text-foreground mb-1'

export default function EditAssignmentModal({
 assignment, consultants, appointmentTypes, planningProjects, onClose, onSaved, onDeleted,
 workModeCapture,
}: Props) {
 // The user always sees a Zeitraum (start + end). For a single-day
 // assignment the two are identical. For a multi-day block they cover
 // the whole connected span. The fetched `blockIds` (below) populates
 // them once the connected days have been resolved.
 const [rangeStart, setRangeStart] = useState(assignment.date)
 const [rangeEnd, setRangeEnd] = useState(assignment.date)
 const [conId, setConId] = useState(assignment.consultant_id)
 const [typeId, setTypeId] = useState(assignment.appointment_type_id)
 const [projectId, setProjectId] = useState(assignment.project_id ??'')
 // tdd-guard:skip — UI-Kompositions-Modal (Supabase-Calls + Fokus/Blur-State), kein isolierbarer purer Kern
 // KAR-704/A1: Freitext -> Stammdaten-Picker. Bestandswerte erscheinen als
 // freetext-Value und bleiben gueltig; neue Auswahl kommt kanonisch aus
 // supplier_master_data (Stufe 2 schreibt zusaetzlich supplier_id nach Migration).
 // Whitespace-only-Bestandswerte laden als leer — das Feld zeigt ehrlich an,
 // was der Save schreiben wird (trim || null).
 const [supplier, setSupplier] = useState<SupplierPickerValue>(
   assignment.supplier_name && assignment.supplier_name.trim() !== ''
     ? { kind:'freetext', freetext: assignment.supplier_name }
     : null,
 )
 const [location, setLocation] = useState(assignment.location_label ??'')
 const [status, setStatus] = useState<AssignmentStatus>(assignment.status)
 const [workMode, setWorkMode] = useState<WorkMode>(assignment.work_mode)
 const [desc, setDesc] = useState(assignment.description ??'')
 const [reqTravel, setReqTravel] = useState(assignment.requires_travel)
 const [saving, setSaving] = useState(false)
 const [deleting, setDeleting] = useState(false)
 const supabase = useMemo(() => createClient(), [])
 const [confirmDel, setConfirmDel] = useState(false)
 const [error, setError] = useState<string | null>(null)
 const [blockIds, setBlockIds] = useState<string[]>([])
 const [blockDates, setBlockDates] = useState<string[]>([assignment.date])

 useEffect(() => {
 const fn = (e: KeyboardEvent) => {
 if (e.key ==='Escape') { if (confirmDel) setConfirmDel(false); else onClose() }
 }
 document.addEventListener('keydown', fn)
 return () => document.removeEventListener('keydown', fn)
 }, [confirmDel, onClose])

 // KAR-704/A1 Stufe 2: bestehenden FK zu einem master_data-Value hydrieren,
 // damit die UI die Stammdaten-Bindung zeigt statt "Freitext". Upgrade nur,
 // solange der Nutzer den initialen Wert noch nicht angefasst hat.
 useEffect(() => {
 if (!assignment.supplier_id) return
 let cancelled = false
 supabase
 .from('supplier_master_data')
 .select('id, supplier_number, supplier_name, supplier_location, plant, country, city')
 .eq('id', assignment.supplier_id)
 .single()
 .then(({ data }) => {
 if (cancelled || !data) return
 setSupplier((prev) =>
 prev?.kind ==='freetext'&& prev.freetext === (assignment.supplier_name ??'')
   ? { kind:'master_data', supplier_id: data.id, supplier: data }
   : prev,
 )
 })
 return () => { cancelled = true }
 }, [assignment.supplier_id, assignment.supplier_name, supabase])

 // Find connected block: same consultant + same project, consecutive workdays
 useEffect(() => {
 if (!assignment.project_id) return
 supabase
 .from('assignments')
 .select('id, date')
 .eq('consultant_id', assignment.consultant_id)
 .eq('project_id', assignment.project_id)
 .order('date')
 .then(({ data }) => {
 if (!data || data.length <= 1) return
 // Build set of dates
 const dateSet = new Map(data.map(a => [a.date as string, a.id as string]))
 // Find contiguous workday block containing this assignment's date
 const connected: string[] = []
 // Walk back from assignment.date
 let cur = new Date(assignment.date +'T00:00:00')
 while (true) {
 const dk = `${cur.getFullYear()}-${String(cur.getMonth()+1).padStart(2,'0')}-${String(cur.getDate()).padStart(2,'0')}`
 if (!dateSet.has(dk)) break
 connected.unshift(dateSet.get(dk)!)
 cur.setDate(cur.getDate() - 1)
 // skip weekends
 while (cur.getDay() === 0 || cur.getDay() === 6) cur.setDate(cur.getDate() - 1)
 }
 // Walk forward
 cur = new Date(assignment.date +'T00:00:00')
 cur.setDate(cur.getDate() + 1)
 while (cur.getDay() === 0 || cur.getDay() === 6) cur.setDate(cur.getDate() + 1)
 while (true) {
 const dk = `${cur.getFullYear()}-${String(cur.getMonth()+1).padStart(2,'0')}-${String(cur.getDate()).padStart(2,'0')}`
 if (!dateSet.has(dk)) break
 connected.push(dateSet.get(dk)!)
 cur.setDate(cur.getDate() + 1)
 while (cur.getDay() === 0 || cur.getDay() === 6) cur.setDate(cur.getDate() + 1)
 }
 if (connected.length > 1) {
 setBlockIds(connected)
 // Resolve dates for the connected ids so we can set start/end.
 const connectedDates = connected
 .map((id) => Array.from(dateSet.entries()).find(([, v]) => v === id)?.[0])
 .filter((d): d is string => !!d)
 .sort()
 if (connectedDates.length) {
 setBlockDates(connectedDates)
 setRangeStart(connectedDates[0])
 setRangeEnd(connectedDates[connectedDates.length - 1])
 }
 }
 })
 }, [assignment.id, assignment.date, assignment.consultant_id, assignment.project_id, supabase])

 // Helper: enumerate every workday between two ISO dates inclusive.
 // Mirrors the resize logic so range-edit produces the same row pattern.
 function datesInRange(start: string, end: string): string[] {
 if (start > end) return []
 const out: string[] = []
 const cur = new Date(start +'T00:00:00')
 const last = new Date(end +'T00:00:00')
 while (cur <= last) {
 const dk = `${cur.getFullYear()}-${String(cur.getMonth()+1).padStart(2,'0')}-${String(cur.getDate()).padStart(2,'0')}`
 out.push(dk)
 cur.setDate(cur.getDate() + 1)
 }
 return out
 }

 async function handleSave(e: React.FormEvent) {
 e.preventDefault()
 if (!rangeStart || !rangeEnd || !conId || !typeId) return
 if (rangeStart > rangeEnd) {
 setError('Start-Datum muss vor oder gleich End-Datum sein')
 return
 }
 setSaving(true)
 setError(null)
 const { data: { user } } = await supabase.auth.getUser()
 const updatePayload = {
 consultant_id: conId,
 appointment_type_id: typeId,
 project_id: projectId || null,
 // KAR-704/A1 Stufe 2: FK-erhaltend — nur eine echte Lieferanten-Änderung
 // löst einen bestehenden supplier_id (siehe lib/planning/supplier-patch.ts)
 ...deriveSupplierPatch(supplier, assignment),
 location_label: location || null,
 description: desc || null,
 // FB-36: capture disabled -> leave work_mode out of the payload so the
 // existing stored value is left untouched by this update.
 ...(workModeCapture ? { work_mode: workMode } : {}),
 status,
 requires_travel: reqTravel,
 updated_by: user?.id ?? null,
 updated_at: new Date().toISOString(),
 }

 // Detect range change vs. simple attribute edit.
 const newDates = datesInRange(rangeStart, rangeEnd)
 const oldDates = blockDates.length ? blockDates : [assignment.date]
 const oldStart = oldDates[0]
 const oldEnd = oldDates[oldDates.length - 1]
 const rangeChanged = rangeStart !== oldStart || rangeEnd !== oldEnd

 if (rangeChanged) {
 // Delete dates outside new range, insert dates not yet present.
 const oldDatesSet = new Set(oldDates)
 const newDatesSet = new Set(newDates)
 const idsToDelete = blockIds.length
 ? blockIds.filter((_, i) => !newDatesSet.has(oldDates[i]))
 : (oldDates[0] !== rangeStart || oldDates[0] !== rangeEnd) && !newDatesSet.has(oldDates[0])
 ? [assignment.id]
 : []
 const datesToInsert = newDates.filter((d) => !oldDatesSet.has(d))

 // Update remaining old rows with new attributes.
 const idsToUpdate = blockIds.length
 ? blockIds.filter((_, i) => newDatesSet.has(oldDates[i]))
 : newDatesSet.has(oldDates[0]) ? [assignment.id] : []
 if (idsToUpdate.length > 0) {
 const { error: updErr } = await supabase.from('assignments').update(updatePayload).in('id', idsToUpdate)
 if (updErr) { setError(updErr.message); setSaving(false); return }
 }

 if (idsToDelete.length > 0) {
 const { error: delErr } = await supabase.from('assignments').delete().in('id', idsToDelete)
 if (delErr) { setError(delErr.message); setSaving(false); return }
 }

 if (datesToInsert.length > 0) {
 const rows = datesToInsert.map((date) => ({
 ...updatePayload,
 date,
 is_all_day: assignment.is_all_day,
 start_time: assignment.start_time,
 end_time: assignment.end_time,
 created_by: user?.id ?? null,
 source:'manual'as const,
 }))
 const { error: insErr } = await supabase.from('assignments').insert(rows)
 if (insErr) { setError(insErr.message); setSaving(false); return }
 }
 } else if (blockIds.length > 1) {
 // Multi-day block: apply attribute changes to every day. The user
 // does not opt in — the previous "Für alle X verbundenen Tage
 // übernehmen" checkbox was removed because connected days are
 // expected to behave as one logical unit (operator decision
 // 2026-05-08).
 const { error: err } = await supabase
 .from('assignments')
 .update(updatePayload)
 .in('id', blockIds)
 if (err) { setError(err.message); setSaving(false); return }
 } else {
 const { error: err } = await supabase
 .from('assignments')
 .update({ ...updatePayload, date: rangeStart })
 .eq('id', assignment.id)
 if (err) { setError(err.message); setSaving(false); return }
 }
 onSaved()
 }

 async function handleDelete() {
 setDeleting(true)
 // Multi-day blocks are stored as one row per day. Deleting only the
 // anchor day leaves the surrounding days behind, which the user reads
 // as "nothing happened". Always delete the connected block.
 const idsToDelete = blockIds.length > 1 ? blockIds : [assignment.id]
 const { error: err } = await supabase.from('assignments').delete().in('id', idsToDelete)
 if (err) { setError(err.message); setDeleting(false); setConfirmDel(false); return }
 onDeleted()
 }

 return (
 <div
 className="fixed inset-0 z-50 bg-black/40 flex items-center justify-center p-4"
 onClick={(e) => e.target === e.currentTarget && onClose()}
 >
 <div className="bg-card text-foreground rounded-xl w-full max-w-md max-h-[90vh] flex flex-col">

 <div className="flex items-center justify-between px-5 py-3.5 border-b border-border shrink-0">
 <h2 className="font-semibold text-[15px] text-foreground">Einsatz bearbeiten</h2>
 <button onClick={onClose} className="w-7 h-7 flex items-center justify-center rounded hover:bg-muted text-[#666]"type="button">✕</button>
 </div>

 <form onSubmit={handleSave} className="px-5 py-4 space-y-3 overflow-y-auto flex-1">

 <div className="grid grid-cols-2 gap-3">
 <div>
 <label className={lbl}>Zeitraum von *</label>
 <input type="date"value={rangeStart} onChange={(e) => {
 const v = e.target.value
 setRangeStart(v)
 if (rangeEnd && v > rangeEnd) setRangeEnd(v)
 }} required className={cls} />
 </div>
 <div>
 <label className={lbl}>Zeitraum bis *</label>
 <input type="date"value={rangeEnd} onChange={(e) => setRangeEnd(e.target.value)} min={rangeStart} required className={cls} />
 </div>
 </div>

 <div>
 <label className={lbl}>Mitarbeiter *</label>
 <select value={conId} onChange={(e) => setConId(e.target.value)} required className={cls}>
 {consultants.filter((c) => c.is_active).map((c) => (
 <option key={c.id} value={c.id}>{c.display_name}</option>
 ))}
 </select>
 </div>

 <div>
 <label className={lbl}>Auftragsart *</label>
 <select value={typeId} onChange={(e) => setTypeId(e.target.value)} required className={cls}>
 {appointmentTypes.map((t) => <option key={t.id} value={t.id}>{t.label}</option>)}
 </select>
 </div>

 <div>
 <label className={lbl}>Projekt (optional)</label>
 <select value={projectId} onChange={(e) => setProjectId(e.target.value)} className={cls}>
 <option value="">— kein Projekt —</option>
 {planningProjects.map((p) => <option key={p.id} value={p.id}>{p.code} — {p.name}</option>)}
 </select>
 </div>

 <div className="grid grid-cols-2 gap-3">
 <div>
 <label className={lbl}>Kunde / Lieferant</label>
 <SupplierPicker value={supplier} onChange={setSupplier}
 placeholder="Lieferant suchen (Name oder Nummer)…"className={cls} />
 </div>
 <div>
 <label className={lbl}>Einsatzort</label>
 <input type="text"value={location} onChange={(e) => setLocation(e.target.value)}
 placeholder="z.B. München…"className={cls} />
 </div>
 </div>

 <div>
 <label className={lbl}>Status *</label>
 <select value={status} onChange={(e) => setStatus(e.target.value as AssignmentStatus)} required className={cls}>
 <option value="fixed">Fest</option>
 <option value="tentative">Vorläufig</option>
 <option value="critical">Kritisch</option>
 <option value="cancelled">Storniert</option>
 </select>
 </div>

 {/* FB-36: hidden entirely when capture is disabled by profile */}
 {workModeCapture && (
 <div>
 <label className={lbl}>Arbeitsort *</label>
 <div className="flex gap-4">
 {(['onsite','homeoffice','remote'] as WorkMode[]).map((m) => (
 <label key={m} className="flex items-center gap-1.5 text-[13px] cursor-pointer select-none">
 <input type="radio"name="workMode"value={m} checked={workMode === m} onChange={() => setWorkMode(m)} className="accent-primary"/>
 {m ==='onsite'?'Vor Ort': m ==='homeoffice'?'Homeoffice':'Remote'}
 </label>
 ))}
 </div>
 </div>
 )}

 <div>
 <label className={lbl}>Bemerkung</label>
 <textarea value={desc} onChange={(e) => setDesc(e.target.value)} rows={2}
 className="w-full rounded border border-muted text-[13px] text-foreground px-2 py-1.5 bg-card focus:outline-none focus:border-primary focus:ring-1 focus:ring-primary resize-none"/>
 </div>

 <label className="flex items-center gap-2 cursor-pointer select-none">
 <input type="checkbox"checked={reqTravel} onChange={(e) => setReqTravel(e.target.checked)}
 className="w-4 h-4 rounded accent-primary"/>
 <span className="text-[13px] text-foreground">✈ Dienstreise (Reisezeit erforderlich)</span>
 </label>

 {blockIds.length > 1 && (
 <div className="bg-[#EFF6FF] border border-[#BFDBFE] rounded-lg px-3 py-2 text-[12px] text-[#1D4ED8]">
 Änderungen werden auf alle {blockIds.length} verbundenen Tage angewendet.
 </div>
 )}

 {confirmDel && (
 <div className="bg-status-red-soft border border-status-red-strong rounded-lg px-3 py-2.5 space-y-2">
 <p className="text-[12px] text-destructive font-medium">Einsatz wirklich löschen?</p>
 <div className="flex gap-2">
 <button type="button"onClick={() => setConfirmDel(false)}
 className="h-7 px-3 text-[12px] rounded border border-muted text-foreground hover:bg-card">Abbrechen</button>
 <button type="button"onClick={handleDelete} disabled={deleting}
 className="h-7 px-3 text-[12px] rounded bg-destructive text-white hover:bg-destructive disabled:opacity-50">
 {deleting ?'Wird gelöscht…':'Ja, löschen'}
 </button>
 </div>
 </div>
 )}

 {error && <p className="text-[12px] text-destructive bg-status-red-soft border border-status-red-strong rounded px-2.5 py-1.5">{error}</p>}
 </form>

 <div className="flex items-center justify-between px-5 py-3 border-t border-border shrink-0">
 <button type="button"onClick={() => setConfirmDel(true)} disabled={confirmDel || deleting}
 className="h-8 px-3 text-[13px] font-medium rounded border border-status-red-strong text-destructive hover:bg-status-red-soft disabled:opacity-40 flex items-center gap-1.5">
 🗑 Löschen
 </button>
 <div className="flex gap-2">
 <button type="button"onClick={onClose}
 className="h-8 px-4 text-[13px] font-medium rounded border border-muted text-foreground hover:bg-muted">Abbrechen</button>
 <button type="button"disabled={saving} onClick={handleSave as unknown as React.MouseEventHandler}
 className="h-8 px-4 text-[13px] font-medium rounded bg-primary text-white hover:bg-primary-dark disabled:opacity-50">
 {saving ?'Speichern…':'Änderungen speichern'}
 </button>
 </div>
 </div>
 </div>
 </div>
 )
}
