// tdd-guard:skip — interactive client modal (form state + supabase reads); behaviour validated via the admin users flow
'use client'

import { useState, useEffect, useMemo } from'react'
import { X } from'lucide-react'
import type { DepartmentMasterData } from'@/lib/repository-types'
import type { UserSession, RoleCode } from'@/lib/auth/permissions-shared'
import { roleLabel } from'@/lib/auth/role-labels'
import { createClient } from'@/lib/supabase/client'

interface Role {
 code: RoleCode
 id: string
 label: string
}

interface UnlinkedConsultant {
 id: string
 display_name: string
 first_name: string
 last_name: string
 team_code: string | null
 department_id: string | null
}

interface Props {
 departments: DepartmentMasterData[]
 // KAR-787 / R53: roles loaded from the DB (set), labels curated via roleLabel()
 roles: Role[]
 session: UserSession
 onClose: () => void
 onCreate: (user: {
 id: string
 first_name: string
 last_name: string
 display_name: string
 email: string
 role_id: string
 department_id: string | null
 account_status: string
 must_change_password: boolean
 last_login_at: null
 created_at: string
 avatar_url: null
 roles: Role | null
 department_master_data: { id: string; department_code: string; department_name: string } | null
 }) => void
}

function getAllowedRoles(actorRole: RoleCode): RoleCode[] {
 switch (actorRole) {
 case'masteradmin': return ['masteradmin','admin','consultant','readonly','extern']
 case'admin': return ['admin','consultant','readonly','extern']
 case'consultant': return ['consultant']
 default: return []
 }
}

const inputCls ='w-full h-10 px-3 rounded-lg border border-border bg-background text-sm focus:outline-none focus:ring-2 focus:ring-primary'
const labelCls ='block text-sm font-medium text-foreground mb-1.5'

export default function CreateUserModal({ departments, roles, session, onClose, onCreate }: Props) {
 const [tab, setTab] = useState<'new'|'link'>('new')

 // ── Tab 1: New user ──────────────────────────────────────────────────────────
 const [firstName, setFirstName] = useState('')
 const [lastName, setLastName] = useState('')
 const [email, setEmail] = useState('')
 const [roleId, setRoleId] = useState('')
 const [deptId, setDeptId] = useState('')
 const [emailConflict, setEmailConflict] = useState(false)
 const [consultantMatch, setConsultantMatch] = useState<{ name: string } | null>(null)
 const [nameMatch, setNameMatch] = useState<{ name: string } | null>(null)
 // KAR-787 / R8: forcing creation despite a detected duplicate needs a reason
 const [forceReason, setForceReason] = useState('')

 // ── Tab 2: Link existing consultant ─────────────────────────────────────────
 const [unlinked, setUnlinked] = useState<UnlinkedConsultant[]>([])
 const [unlinkedLoading, setUnlinkedLoading] = useState(false)
 const [selectedConsultant, setSelectedConsultant] = useState<UnlinkedConsultant | null>(null)
 const [linkSearch, setLinkSearch] = useState('')
 const [linkEmail, setLinkEmail] = useState('')
 const [linkRoleId, setLinkRoleId] = useState('')

 const [saving, setSaving] = useState(false)
 const supabase = useMemo(() => createClient(), [])
 const [error, setError] = useState<string | null>(null)

 const allowedRoleCodes = getAllowedRoles(session.role)

 // Fetch unlinked consultants when switching to tab 2
 useEffect(() => {
 if (tab !=='link') return
 setUnlinkedLoading(true)
 supabase
 .from('consultants')
 .select('id, display_name, first_name, last_name, team_code, department_id')
 .is('auth_user_id', null)
 .eq('is_active', true)
 .order('last_name')
 .then(({ data }) => {
 setUnlinked((data as UnlinkedConsultant[]) ?? [])
 setUnlinkedLoading(false)
 })
 }, [tab])

 function selectConsultant(c: UnlinkedConsultant) {
 setSelectedConsultant(c)
 setFirstName(c.first_name)
 setLastName(c.last_name)
 setDeptId(c.department_id ??'')
 setLinkSearch(c.display_name)
 }

 async function handleEmailBlur() {
 const trimmed = email.trim()
 if (!trimmed) { setEmailConflict(false); setConsultantMatch(null); return }
 try {
 const { data } = await supabase.rpc('check_email_in_profiles', { check_email: trimmed })
 const result = data as { exists?: boolean; linked?: boolean } | null
 setEmailConflict(!!(result?.exists && result?.linked))
 // R6/R10: the RPC only checks user_profiles. Also catch a consultant with the
 // same email — otherwise a duplicate person record slips through the dedup.
 const { data: cons } = await supabase
 .from('consultants').select('display_name').ilike('email', trimmed).limit(1)
 const c = (cons as { display_name: string }[] | null)?.[0]
 setConsultantMatch(c ? { name: c.display_name } : null)
 } catch {
 setEmailConflict(false); setConsultantMatch(null)
 }
 }

 // R46: warn when an unlinked consultant with the same name already exists, so the
 // admin links the existing person (Tab 2) instead of creating a duplicate.
 async function handleNameBlur() {
 const fn = firstName.trim(), ln = lastName.trim()
 if (!fn || !ln) { setNameMatch(null); return }
 try {
 const { data } = await supabase
 .from('consultants').select('display_name')
 .ilike('first_name', fn).ilike('last_name', ln).is('auth_user_id', null).limit(1)
 const c = (data as { display_name: string }[] | null)?.[0]
 setNameMatch(c ? { name: c.display_name } : null)
 } catch { setNameMatch(null) }
 }

 async function handleSubmit(e: React.FormEvent) {
 e.preventDefault()
 const isLink = tab ==='link'

 const fn = isLink ? (selectedConsultant?.first_name ?? firstName) : firstName
 const ln = isLink ? (selectedConsultant?.last_name ?? lastName) : lastName
 const mail = isLink ? linkEmail.trim() : email.trim()
 const role = isLink ? linkRoleId : roleId
 const dept = isLink ? (selectedConsultant?.department_id ?? deptId) : deptId

 if (!fn.trim() || !ln.trim() || !mail || !role) {
 setError('Bitte alle Pflichtfelder ausfüllen.')
 return
 }
 if (isLink && !selectedConsultant) {
 setError('Bitte einen Mitarbeiter auswählen.')
 return
 }

 // KAR-787 / R8: a detected duplicate (email already used, or a consultant/
 // name match) may only be force-created by an admin/masteradmin, and only
 // with a documented reason — which is sent to the audit log.
 const hasDuplicateSignal = !isLink && (emailConflict || !!consultantMatch || !!nameMatch)
 if (hasDuplicateSignal) {
 if (session.role !=='admin'&& session.role !=='masteradmin') {
 setError('Es existiert bereits ein Datensatz mit diesen Daten. Nur Admin/Masteradmin dürfen trotzdem neu anlegen.')
 return
 }
 if (!forceReason.trim()) {
 setError('Dublette erkannt — bitte eine Begründung für die Doppelanlage angeben.')
 return
 }
 }

 setSaving(true)
 setError(null)

 const res = await fetch('/api/admin/users', {
 method:'POST',
 headers: {'Content-Type':'application/json'},
 body: JSON.stringify({
 first_name: fn.trim(),
 last_name: ln.trim(),
 email: mail,
 role_id: role,
 department_id: dept || null,
 ...(isLink && selectedConsultant ? { consultant_id: selectedConsultant.id } : {}),
 ...(hasDuplicateSignal ? { force_create_reason: forceReason.trim() } : {}),
 }),
 })

 if (!res.ok) {
 let errorMsg = `Server-Fehler (${res.status})`
 try {
 const data = await res.json() as { error?: string }
 errorMsg = data.error ?? errorMsg
 } catch { /* empty */ }
 setError(errorMsg)
 setSaving(false)
 return
 }

 const { profile } = await res.json() as {
 profile: {
 id: string; first_name: string; last_name: string; display_name: string; email: string
 role_id: string; department_id: string | null; account_status: string
 must_change_password: boolean; last_login_at: null; created_at: string; avatar_url: null
 }
 }

 const roleMeta = roles.find((r) => r.id === role || r.code === role) ?? null
 const deptMeta = departments.find((d) => d.id === dept) ?? null

 onCreate({
 ...profile,
 roles: roleMeta ? { code: roleMeta.code, id: role, label: roleLabel(roleMeta.code, roleMeta.label) } : null,
 department_master_data: deptMeta
 ? { id: deptMeta.id, department_code: deptMeta.department_code, department_name: deptMeta.department_name }
 : null,
 })
 }

 const filteredUnlinked = linkSearch
 ? unlinked.filter((c) =>
 c.display_name.toLowerCase().includes(linkSearch.toLowerCase()) ||
 (c.team_code ??'').toLowerCase().includes(linkSearch.toLowerCase())
 )
 : unlinked

 // KAR-787 / R8: show the force-create reason field once a duplicate is flagged.
 const showForceReason = tab ==='new'&& (emailConflict || !!consultantMatch || !!nameMatch)
 const canForceCreate = session.role ==='admin'|| session.role ==='masteradmin'

 return (
 <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4">
 <div className="bg-card text-foreground rounded-sm w-full max-w-md overflow-hidden">
 {/* Header */}
 <div className="bg-primary-dark px-6 py-5 flex items-center justify-between">
 <h2 className="font-bold text-white text-lg">Benutzer hinzufügen</h2>
 <button onClick={onClose} className="text-white/60 hover:text-white transition-colors">
 <X size={20} />
 </button>
 </div>

 {/* Tab toggle */}
 <div className="flex border-b border-border">
 {[
 { key:'new', label:'Neuen Benutzer anlegen'},
 { key:'link', label:'Mitarbeiter verknüpfen'},
 ].map(({ key, label }) => (
 <button
 key={key}
 onClick={() => { setTab(key as'new'|'link'); setError(null) }}
 className={[
'flex-1 py-2.5 text-[13px] font-medium border-b-2 transition-colors',
 tab === key
 ?'border-primary text-primary'
 :'border-transparent text-muted-foreground hover:text-foreground',
 ].join('')}
 >
 {label}
 </button>
 ))}
 </div>

 <form onSubmit={(e) => void handleSubmit(e)} className="px-6 py-6 space-y-4">

 {/* ── TAB 1: New user ─────────────────────────────────────────────── */}
 {tab ==='new'&& (
 <>
 <div className="grid grid-cols-2 gap-3">
 <div>
 <label className={labelCls}>Vorname <span className="text-destructive">*</span></label>
 <input value={firstName} onChange={(e) => { setFirstName(e.target.value); setNameMatch(null) }}
 onBlur={() => void handleNameBlur()}
 className={inputCls} placeholder="Max"required />
 </div>
 <div>
 <label className={labelCls}>Nachname <span className="text-destructive">*</span></label>
 <input value={lastName} onChange={(e) => { setLastName(e.target.value); setNameMatch(null) }}
 onBlur={() => void handleNameBlur()}
 className={inputCls} placeholder="Mustermann"required />
 </div>
 </div>
 {nameMatch && (
 <p className="-mt-2 text-xs text-amber-600">
 Ein Berater „{nameMatch.name}" mit diesem Namen existiert bereits — ggf. im Tab „Bestehenden verknüpfen" auswählen statt neu anlegen.
 </p>
 )}

 <div>
 <label className={labelCls}>E-Mail <span className="text-destructive">*</span></label>
 <input
 type="email"value={email}
 onChange={(e) => { setEmail(e.target.value); setEmailConflict(false); setConsultantMatch(null) }}
 onBlur={() => void handleEmailBlur()}
 className={`${inputCls} ${emailConflict ?'border-destructive':''}`}
 placeholder="max.mustermann@example.com"required
 />
 {emailConflict && (
 <p className="mt-1 text-xs text-destructive">Ein Benutzer mit dieser E-Mail existiert bereits.</p>
 )}
 {!emailConflict && consultantMatch && (
 <p className="mt-1 text-xs text-amber-600">
 Ein Berater „{consultantMatch.name}" mit dieser E-Mail existiert bereits — im Tab „Bestehenden verknüpfen" auswählen statt neu anlegen.
 </p>
 )}
 </div>

 {/* KAR-787 / R8: force-create-despite-duplicate gate */}
 {showForceReason && (
 <div className="rounded-lg border border-amber-300 bg-amber-50 p-3">
 {canForceCreate ? (
 <>
 <label className="block text-sm font-medium text-amber-800 mb-1.5">
 Begründung für Doppelanlage <span className="text-destructive">*</span>
 </label>
 <textarea
 value={forceReason}
 onChange={(e) => setForceReason(e.target.value)}
 rows={2}
 className="w-full px-3 py-2 rounded-lg border border-amber-300 bg-background text-sm focus:outline-none focus:ring-2 focus:ring-primary resize-none"
 placeholder="Warum trotz erkannter Dublette neu anlegen? (wird protokolliert)"
 />
 </>
 ) : (
 <p className="text-xs text-amber-800">
 Es existiert bereits ein Datensatz mit diesen Daten. Nur Admin/Masteradmin dürfen trotzdem neu anlegen.
 </p>
 )}
 </div>
 )}

 <div>
 <label className={labelCls}>Rolle <span className="text-destructive">*</span></label>
 <select value={roleId} onChange={(e) => setRoleId(e.target.value)}
 className={inputCls} required>
 <option value="">Rolle wählen…</option>
 {allowedRoleCodes.map((code) => {
 const r = roles.find((x) => x.code === code)
 return r ? <option key={code} value={code}>{roleLabel(code, r.label)}</option> : null
 })}
 </select>
 </div>

 <div>
 <label className={labelCls}>Abteilung</label>
 <select value={deptId} onChange={(e) => setDeptId(e.target.value)} className={inputCls}>
 <option value="">Keine Abteilung</option>
 {departments.map((d) => (
 <option key={d.id} value={d.id}>{d.department_code}</option>
 ))}
 </select>
 </div>
 </>
 )}

 {/* ── TAB 2: Link existing consultant ─────────────────────────────── */}
 {tab ==='link'&& (
 <>
 <div>
 <label className={labelCls}>Mitarbeiter auswählen <span className="text-destructive">*</span></label>
 <input
 value={linkSearch}
 onChange={(e) => { setLinkSearch(e.target.value); setSelectedConsultant(null) }}
 className={inputCls}
 placeholder="Name oder Abteilung suchen…"
 />
 {linkSearch && !selectedConsultant && filteredUnlinked.length > 0 && (
 <div className="mt-1 border border-border rounded-lg bg-card max-h-40 overflow-y-auto">
 {unlinkedLoading ? (
 <p className="px-3 py-2 text-sm text-muted-foreground">Lädt…</p>
 ) : (
 filteredUnlinked.map((c) => (
 <button
 key={c.id} type="button"
 onClick={() => selectConsultant(c)}
 className="w-full text-left px-3 py-2 text-sm hover:bg-background transition-colors"
 >
 <span className="font-medium text-foreground">{c.display_name}</span>
 {c.team_code && (
 <span className="ml-2 text-xs text-muted-foreground">{c.team_code}</span>
 )}
 </button>
 ))
 )}
 {!unlinkedLoading && filteredUnlinked.length === 0 && (
 <p className="px-3 py-2 text-sm text-muted-foreground italic">Keine Ergebnisse.</p>
 )}
 </div>
 )}
 {selectedConsultant && (
 <p className="mt-1 text-xs text-success">
 ✓ {selectedConsultant.display_name} ausgewählt
 </p>
 )}
 </div>

 {selectedConsultant && (
 <>
 <div className="grid grid-cols-2 gap-3 text-sm text-muted-foreground bg-background rounded-lg px-3 py-2 border border-border">
 <div><span className="block text-[11px] font-medium mb-0.5">Vorname</span>{selectedConsultant.first_name}</div>
 <div><span className="block text-[11px] font-medium mb-0.5">Nachname</span>{selectedConsultant.last_name}</div>
 </div>

 <div>
 <label className={labelCls}>E-Mail <span className="text-destructive">*</span></label>
 <input
 type="email"value={linkEmail}
 onChange={(e) => setLinkEmail(e.target.value)}
 className={inputCls} placeholder="email@example.com"required
 />
 </div>

 <div>
 <label className={labelCls}>Rolle <span className="text-destructive">*</span></label>
 <select value={linkRoleId} onChange={(e) => setLinkRoleId(e.target.value)}
 className={inputCls} required>
 <option value="">Rolle wählen…</option>
 {allowedRoleCodes.map((code) => {
 const r = roles.find((x) => x.code === code)
 return r ? <option key={code} value={code}>{roleLabel(code, r.label)}</option> : null
 })}
 </select>
 </div>
 </>
 )}

 {!selectedConsultant && !unlinkedLoading && unlinked.length === 0 && (
 <p className="text-sm text-muted-foreground italic py-2">
 Alle aktiven Mitarbeiter sind bereits verknüpft.
 </p>
 )}
 </>
 )}

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

 <div className="flex gap-3 pt-2">
 <button type="button"onClick={onClose}
 className="flex-1 h-10 rounded-lg border border-border text-sm text-muted-foreground hover:bg-background transition-colors">
 Abbrechen
 </button>
 <button type="submit"disabled={saving || (tab ==='link'&& !selectedConsultant)}
 className="flex-1 h-10 bg-primary text-white rounded-lg text-sm font-semibold hover:bg-primary/90 disabled:opacity-50 transition-colors">
 {saving ?'Erstellen…':'Benutzer erstellen'}
 </button>
 </div>
 </form>
 </div>
 </div>
 )
}
