import { useEffect, useState, useRef, useCallback } from 'react'
import peopleApi, { PersonWithFaces, PersonFaceItem, PersonUpdateRequest } from '../api/people'
import facesApi from '../api/faces'

interface EditDialogProps {
  person: PersonWithFaces
  onSave: (personId: number, data: PersonUpdateRequest) => Promise<void>
  onClose: () => void
}

function EditPersonDialog({ person, onSave, onClose }: EditDialogProps) {
  const [firstName, setFirstName] = useState(person.first_name || '')
  const [lastName, setLastName] = useState(person.last_name || '')
  const [middleName, setMiddleName] = useState(person.middle_name || '')
  const [maidenName, setMaidenName] = useState(person.maiden_name || '')
  const [dob, setDob] = useState(person.date_of_birth || '')
  const [busy, setBusy] = useState(false)
  const [error, setError] = useState<string | null>(null)

  const canSave = firstName.trim() && lastName.trim()

  const handleSave = async () => {
    if (!canSave || busy) return

    setBusy(true)
    setError(null)

    try {
      await onSave(person.id, {
        first_name: firstName.trim(),
        last_name: lastName.trim(),
        middle_name: middleName.trim() || undefined,
        maiden_name: maidenName.trim() || undefined,
        date_of_birth: dob.trim() || null,
      })
      onClose()
    } catch (err: any) {
      setError(err.response?.data?.detail || err.message || 'Failed to update person')
    } finally {
      setBusy(false)
    }
  }

  const handleKeyDown = (e: React.KeyboardEvent) => {
    if (e.key === 'Enter' && canSave && !busy) {
      handleSave()
    } else if (e.key === 'Escape') {
      onClose()
    }
  }

  return (
    <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
      <div className="bg-white rounded-lg shadow-xl w-full max-w-md p-6">
        <h2 className="text-xl font-bold mb-4">Edit {person.first_name} {person.last_name}</h2>

        {error && (
          <div className="mb-4 p-3 bg-red-50 border border-red-200 rounded text-red-700 text-sm">
            {error}
          </div>
        )}

        <div className="space-y-4">
          <div>
            <label className="block text-sm font-medium text-gray-700 mb-1">
              First name <span className="text-red-500">*</span>
            </label>
            <input
              type="text"
              value={firstName}
              onChange={(e) => setFirstName(e.target.value)}
              onKeyDown={handleKeyDown}
              className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
              autoFocus
            />
          </div>

          <div>
            <label className="block text-sm font-medium text-gray-700 mb-1">
              Last name <span className="text-red-500">*</span>
            </label>
            <input
              type="text"
              value={lastName}
              onChange={(e) => setLastName(e.target.value)}
              onKeyDown={handleKeyDown}
              className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
            />
          </div>

          <div>
            <label className="block text-sm font-medium text-gray-700 mb-1">Middle name</label>
            <input
              type="text"
              value={middleName}
              onChange={(e) => setMiddleName(e.target.value)}
              onKeyDown={handleKeyDown}
              className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
            />
          </div>

          <div>
            <label className="block text-sm font-medium text-gray-700 mb-1">Maiden name</label>
            <input
              type="text"
              value={maidenName}
              onChange={(e) => setMaidenName(e.target.value)}
              onKeyDown={handleKeyDown}
              className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
            />
          </div>

          <div>
            <label className="block text-sm font-medium text-gray-700 mb-1">Date of birth</label>
            <input
              type="date"
              value={dob}
              onChange={(e) => setDob(e.target.value)}
              onKeyDown={handleKeyDown}
              className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
            />
          </div>
        </div>

        <div className="mt-6 flex justify-end gap-3">
          <button
            onClick={onClose}
            disabled={busy}
            className="px-4 py-2 text-gray-700 bg-gray-100 rounded-md hover:bg-gray-200 disabled:opacity-50"
          >
            Cancel
          </button>
          <button
            onClick={handleSave}
            disabled={!canSave || busy}
            className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed"
          >
            {busy ? 'Saving...' : 'Save'}
          </button>
        </div>
      </div>
    </div>
  )
}

export default function Modify() {
  const [people, setPeople] = useState<PersonWithFaces[]>([])
  const [lastNameFilter, setLastNameFilter] = useState('')
  const [selectedPersonId, setSelectedPersonId] = useState<number | null>(null)
  const [selectedPersonName, setSelectedPersonName] = useState('')
  const [faces, setFaces] = useState<PersonFaceItem[]>([])
  const [unmatchedFaces, setUnmatchedFaces] = useState<Set<number>>(new Set())
  const [unmatchedByPerson, setUnmatchedByPerson] = useState<Record<number, Set<number>>>({})
  const [selectedFaces, setSelectedFaces] = useState<Set<number>>(new Set())
  const [editDialogPerson, setEditDialogPerson] = useState<PersonWithFaces | null>(null)
  const [busy, setBusy] = useState(false)
  const [error, setError] = useState<string | null>(null)
  const [success, setSuccess] = useState<string | null>(null)

  const gridRef = useRef<HTMLDivElement>(null)

  // Load people with faces
  const loadPeople = useCallback(async () => {
    try {
      setBusy(true)
      setError(null)
      const res = await peopleApi.listWithFaces(lastNameFilter || undefined)
      setPeople(res.items)
      
      // Auto-select first person if available and none selected
      if (res.items.length > 0 && !selectedPersonId) {
        const firstPerson = res.items[0]
        setSelectedPersonId(firstPerson.id)
        setSelectedPersonName(formatPersonName(firstPerson))
        loadPersonFaces(firstPerson.id)
      }
    } catch (err: any) {
      setError(err.response?.data?.detail || err.message || 'Failed to load people')
    } finally {
      setBusy(false)
    }
  }, [lastNameFilter, selectedPersonId])

  // Load faces for a person
  const loadPersonFaces = useCallback(async (personId: number) => {
    try {
      setBusy(true)
      setError(null)
      const res = await peopleApi.getFaces(personId)
      // Filter out unmatched faces (show only matched faces)
      const visibleFaces = res.items.filter((f) => !unmatchedFaces.has(f.id))
      setFaces(visibleFaces)
    } catch (err: any) {
      // If person not found (404), clear selection instead of showing error
      // This can happen if person was deleted after selection
      const errorDetail = err.response?.data?.detail || err.message || ''
      if (err.response?.status === 404 && errorDetail.includes('Person') && errorDetail.includes('not found')) {
        setSelectedPersonId(null)
        setSelectedPersonName('')
        setFaces([])
        setError(null) // Don't show error for deleted person
      } else {
        setError(errorDetail || 'Failed to load faces')
      }
    } finally {
      setBusy(false)
    }
  }, [unmatchedFaces])

  useEffect(() => {
    loadPeople()
  }, [loadPeople])

  // Reload faces when person changes
  useEffect(() => {
    if (selectedPersonId) {
      loadPersonFaces(selectedPersonId)
      // Clear selected faces when person changes
      setSelectedFaces(new Set())
    }
  }, [selectedPersonId, loadPersonFaces])

  const formatPersonName = (person: PersonWithFaces): string => {
    const parts: string[] = []
    if (person.first_name) parts.push(person.first_name)
    if (person.middle_name) parts.push(person.middle_name)
    if (person.last_name) parts.push(person.last_name)
    if (person.maiden_name) parts.push(`(${person.maiden_name})`)
    const name = parts.join(' ') || 'Unknown'
    if (person.date_of_birth) {
      return `${name} - Born: ${person.date_of_birth}`
    }
    return name
  }

  const handleSearch = () => {
    loadPeople()
  }

  const handleClearSearch = () => {
    setLastNameFilter('')
    // loadPeople will be called by useEffect
  }

  const handlePersonClick = (person: PersonWithFaces) => {
    setSelectedPersonId(person.id)
    setSelectedPersonName(formatPersonName(person))
    loadPersonFaces(person.id)
  }

  const handleEditPerson = (person: PersonWithFaces) => {
    setEditDialogPerson(person)
  }

  const handleSavePerson = async (personId: number, data: PersonUpdateRequest) => {
    await peopleApi.update(personId, data)
    // Reload people list
    await loadPeople()
    // Reload faces if this is the selected person
    if (selectedPersonId === personId) {
      await loadPersonFaces(personId)
    }
    setSuccess('Person information updated successfully')
    setTimeout(() => setSuccess(null), 3000)
  }

  const handleUnmatchFace = async (faceId: number) => {
    // Add to unmatched set (temporary, not persisted until save)
    const newUnmatched = new Set(unmatchedFaces)
    newUnmatched.add(faceId)
    setUnmatchedFaces(newUnmatched)

    // Track by person
    if (selectedPersonId) {
      const newByPerson = { ...unmatchedByPerson }
      if (!newByPerson[selectedPersonId]) {
        newByPerson[selectedPersonId] = new Set()
      }
      newByPerson[selectedPersonId].add(faceId)
      setUnmatchedByPerson(newByPerson)
    }

    // Remove from selected faces
    const newSelected = new Set(selectedFaces)
    newSelected.delete(faceId)
    setSelectedFaces(newSelected)

    // Immediately refresh display to hide unmatched face
    if (selectedPersonId) {
      await loadPersonFaces(selectedPersonId)
    }
  }

  const handleToggleFaceSelection = (faceId: number) => {
    const newSelected = new Set(selectedFaces)
    if (newSelected.has(faceId)) {
      newSelected.delete(faceId)
    } else {
      newSelected.add(faceId)
    }
    setSelectedFaces(newSelected)
  }

  const handleSelectAll = () => {
    const allFaceIds = new Set(visibleFaces.map(f => f.id))
    setSelectedFaces(allFaceIds)
  }

  const handleUnselectAll = () => {
    setSelectedFaces(new Set())
  }

  const handleBulkUnmatch = async () => {
    if (selectedFaces.size === 0) return

    try {
      setBusy(true)
      setError(null)

      // Add all selected faces to unmatched set
      const newUnmatched = new Set(unmatchedFaces)
      const faceIds = Array.from(selectedFaces)
      faceIds.forEach(id => newUnmatched.add(id))
      setUnmatchedFaces(newUnmatched)

      // Track by person
      if (selectedPersonId) {
        const newByPerson = { ...unmatchedByPerson }
        if (!newByPerson[selectedPersonId]) {
          newByPerson[selectedPersonId] = new Set()
        }
        faceIds.forEach(id => newByPerson[selectedPersonId].add(id))
        setUnmatchedByPerson(newByPerson)
      }

      // Clear selected faces
      setSelectedFaces(new Set())

      // Immediately refresh display to hide unmatched faces
      if (selectedPersonId) {
        await loadPersonFaces(selectedPersonId)
      }

      setSuccess(`Marked ${faceIds.length} face(s) for unmatching`)
      setTimeout(() => setSuccess(null), 3000)
    } catch (err: any) {
      setError(err.response?.data?.detail || err.message || 'Failed to unmatch faces')
    } finally {
      setBusy(false)
    }
  }

  const handleUndoChanges = () => {
    if (!selectedPersonId) return

    const personFaces = unmatchedByPerson[selectedPersonId]
    if (!personFaces || personFaces.size === 0) return

    // Remove faces for current person from unmatched sets
    const newUnmatched = new Set(unmatchedFaces)
    for (const faceId of personFaces) {
      newUnmatched.delete(faceId)
    }
    setUnmatchedFaces(newUnmatched)

    const newByPerson = { ...unmatchedByPerson }
    delete newByPerson[selectedPersonId]
    setUnmatchedByPerson(newByPerson)

    // Clear selected faces
    setSelectedFaces(new Set())

    // Reload faces to show restored faces
    if (selectedPersonId) {
      loadPersonFaces(selectedPersonId)
    }

    setSuccess(`Undid changes for ${personFaces.size} face(s)`)
    setTimeout(() => setSuccess(null), 3000)
  }

  const handleSaveChanges = async () => {
    if (unmatchedFaces.size === 0) return

    try {
      setBusy(true)
      setError(null)

      // Batch unmatch all faces
      const faceIds = Array.from(unmatchedFaces)
      await facesApi.batchUnmatch({ face_ids: faceIds })

      // Clear unmatched sets
      setUnmatchedFaces(new Set())
      setUnmatchedByPerson({})
      setSelectedFaces(new Set())

      // Reload people list first to update face counts and check if person still exists
      const peopleRes = await peopleApi.listWithFaces(lastNameFilter || undefined)
      
      // Check if selected person still exists BEFORE updating state
      // This prevents useEffect from triggering unnecessary requests
      const currentSelectedId = selectedPersonId
      const personStillExists = currentSelectedId 
        ? peopleRes.items.some(p => p.id === currentSelectedId)
        : false
      
      // Clear selection immediately if person was deleted (before state update)
      if (currentSelectedId && !personStillExists) {
        setSelectedPersonId(null)
        setSelectedPersonName('')
        setFaces([])
        setError(null)
      }
      
      // Update people list
      setPeople(peopleRes.items)

      // Reload faces only if person still exists
      if (currentSelectedId && personStillExists) {
        await loadPersonFaces(currentSelectedId)
      }

      setSuccess(`Successfully unlinked ${faceIds.length} face(s)`)
      setTimeout(() => setSuccess(null), 3000)
    } catch (err: any) {
      setError(err.response?.data?.detail || err.message || 'Failed to save changes')
    } finally {
      setBusy(false)
    }
  }

  const visibleFaces = faces.filter((f) => !unmatchedFaces.has(f.id))
  const currentPersonHasUnmatched = selectedPersonId
    ? Boolean(unmatchedByPerson[selectedPersonId]?.size)
    : false

  return (
    <div className="space-y-6">
      <h1 className="text-3xl font-bold">✏️ Modify Identified</h1>

      {error && (
        <div className="p-4 bg-red-50 border border-red-200 rounded text-red-700">
          {error}
        </div>
      )}

      {success && (
        <div className="p-4 bg-green-50 border border-green-200 rounded text-green-700">
          {success}
        </div>
      )}

      <div className="grid grid-cols-3 gap-6">
        {/* Left panel: People list */}
        <div className="col-span-1">
          <div className="bg-white rounded-lg shadow p-4 h-full flex flex-col">
            <h2 className="text-lg font-semibold mb-4">People</h2>

            {/* Search controls */}
            <div className="mb-4">
              <div className="flex gap-2 mb-1">
                <input
                  type="text"
                  value={lastNameFilter}
                  onChange={(e) => setLastNameFilter(e.target.value)}
                  onKeyDown={(e) => e.key === 'Enter' && handleSearch()}
                  placeholder="Type Last Name or Maiden Name"
                  className="flex-1 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
                />
                <button
                  onClick={handleSearch}
                  className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700"
                >
                  Search
                </button>
                <button
                  onClick={handleClearSearch}
                  className="px-4 py-2 bg-gray-100 text-gray-700 rounded-md hover:bg-gray-200"
                >
                  Clear
                </button>
              </div>
              <p className="text-xs text-gray-500">Search by Last Name or Maiden Name</p>
            </div>

            {/* People list */}
            <div className="flex-1 overflow-y-auto">
              {busy && people.length === 0 ? (
                <div className="text-center text-gray-500 py-8">Loading...</div>
              ) : people.length === 0 ? (
                <div className="text-center text-gray-500 py-8">No people found</div>
              ) : (
                <div className="space-y-2">
                  {people.map((person) => {
                    const isSelected = selectedPersonId === person.id
                    const name = formatPersonName(person)
                    return (
                      <div
                        key={person.id}
                        className={`flex items-center gap-2 p-2 rounded hover:bg-gray-50 cursor-pointer ${
                          isSelected ? 'bg-blue-50 font-semibold' : ''
                        }`}
                      >
                        <button
                          onClick={(e) => {
                            e.stopPropagation()
                            handleEditPerson(person)
                          }}
                          className="text-sm px-2 py-1 hover:bg-gray-200 rounded"
                          title="Update name"
                        >
                          ✏️
                        </button>
                        <div
                          onClick={() => handlePersonClick(person)}
                          className="flex-1"
                        >
                          {name} ({person.face_count})
                        </div>
                      </div>
                    )
                  })}
                </div>
              )}
            </div>
          </div>
        </div>

        {/* Right panel: Faces grid */}
        <div className="col-span-2">
          <div className="bg-white rounded-lg shadow p-4 h-full flex flex-col">
            <div className="flex items-center justify-between mb-4">
              <h2 className="text-lg font-semibold">Faces</h2>
              {selectedPersonId && (
                <div className="flex gap-2">
                  {visibleFaces.length > 0 && (
                    <>
                      <button
                        onClick={handleSelectAll}
                        disabled={busy}
                        className="px-3 py-1 text-sm bg-gray-100 text-gray-700 rounded hover:bg-gray-200 disabled:opacity-50 disabled:cursor-not-allowed"
                      >
                        Select All
                      </button>
                      <button
                        onClick={handleUnselectAll}
                        disabled={busy || selectedFaces.size === 0}
                        className="px-3 py-1 text-sm bg-gray-100 text-gray-700 rounded hover:bg-gray-200 disabled:opacity-50 disabled:cursor-not-allowed"
                      >
                        Unselect All
                      </button>
                      <button
                        onClick={handleBulkUnmatch}
                        disabled={busy || selectedFaces.size === 0}
                        className="px-3 py-1 text-sm bg-red-600 text-white rounded hover:bg-red-700 disabled:opacity-50 disabled:cursor-not-allowed"
                      >
                        Unmatch Selected
                      </button>
                    </>
                  )}
                  <button
                    onClick={handleUndoChanges}
                    disabled={!currentPersonHasUnmatched || busy}
                    className="px-3 py-1 text-sm bg-gray-100 text-gray-700 rounded hover:bg-gray-200 disabled:opacity-50 disabled:cursor-not-allowed"
                  >
                    ↶ Undo changes
                  </button>
                  <button
                    onClick={handleSaveChanges}
                    disabled={unmatchedFaces.size === 0 || busy}
                    className="px-3 py-1 text-sm bg-blue-600 text-white rounded hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed"
                  >
                    💾 Save changes
                  </button>
                </div>
              )}
            </div>

            {selectedPersonId ? (
              <div className="flex-1 overflow-y-auto">
                {busy && visibleFaces.length === 0 ? (
                  <div className="text-center text-gray-500 py-8">Loading faces...</div>
                ) : visibleFaces.length === 0 ? (
                  <div className="text-center text-gray-500 py-8">
                    {faces.length === 0
                      ? 'No faces found for this person'
                      : 'All faces unmatched'}
                  </div>
                ) : (
                  <div
                    ref={gridRef}
                    className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-4"
                  >
                    {visibleFaces.map((face) => (
                      <div key={face.id} className="flex flex-col items-center">
                        <div className="w-20 h-20 mb-2">
                          <img
                            src={`/api/v1/faces/${face.id}/crop`}
                            alt={`Face ${face.id}`}
                            className="w-full h-full object-cover rounded cursor-pointer hover:opacity-80 transition-opacity"
                            onClick={() => {
                              // Open photo in new window
                              window.open(`/api/v1/photos/${face.photo_id}/image`, '_blank')
                            }}
                            title="Click to show original photo"
                            onError={(e) => {
                              e.currentTarget.src = '/placeholder.png'
                            }}
                          />
                        </div>
                        <label className="flex items-center gap-1 cursor-pointer">
                          <input
                            type="checkbox"
                            checked={selectedFaces.has(face.id)}
                            onChange={() => handleToggleFaceSelection(face.id)}
                            className="rounded"
                            disabled={busy}
                          />
                          <span className="text-xs text-gray-700">Unmatch</span>
                        </label>
                      </div>
                    ))}
                  </div>
                )}
              </div>
            ) : (
              <div className="text-center text-gray-500 py-8">
                Select a person to view their faces
              </div>
            )}
          </div>
        </div>
      </div>

      {/* Edit person dialog */}
      {editDialogPerson && (
        <EditPersonDialog
          person={editDialogPerson}
          onSave={handleSavePerson}
          onClose={() => setEditDialogPerson(null)}
        />
      )}
    </div>
  )
}

