import { useState, useEffect, useCallback, useRef, useMemo } from 'react'
import { RefreshCw, ChevronDown, Search, GitBranch } from 'lucide-react'
import { cn } from '@/lib/utils'
import { useGitStore } from '@/stores/useGitStore'
import { useWorktreeStore } from '@/stores/useWorktreeStore'
import { useFileViewerStore } from '@/stores/useFileViewerStore'
import { FileIcon } from './FileIcon'
import { GitStatusIndicator, type GitStatusCode } from './GitStatusIndicator'
import { useI18n } from '@/i18n/useI18n'

interface BranchDiffViewProps {
  worktreePath: string | null
}

interface BranchDiffFile {
  relativePath: string
  status: string
}

interface BranchInfo {
  name: string
  isRemote: boolean
  isCheckedOut: boolean
  worktreePath?: string
}

const KNOWN_STATUS_CODES: GitStatusCode[] = ['M', 'A', 'D', '?', 'C', '']

function toGitStatusCode(raw: string): GitStatusCode {
  return KNOWN_STATUS_CODES.includes(raw as GitStatusCode) ? (raw as GitStatusCode) : 'M'
}

export function BranchDiffView({ worktreePath }: BranchDiffViewProps): React.JSX.Element {
  const { t } = useI18n()
  const selectedDiffBranch = useGitStore((state) => state.selectedDiffBranch)
  const setSelectedDiffBranch = useGitStore((state) => state.setSelectedDiffBranch)
  const selectedWorktreeId = useWorktreeStore((state) => state.selectedWorktreeId)

  const selectedBranch = worktreePath ? (selectedDiffBranch.get(worktreePath) ?? null) : null

  const [branches, setBranches] = useState<BranchInfo[]>([])
  const [files, setFiles] = useState<BranchDiffFile[]>([])
  const [isLoadingFiles, setIsLoadingFiles] = useState(false)
  const [diffError, setDiffError] = useState<string | null>(null)
  const [isLoadingBranches, setIsLoadingBranches] = useState(false)
  const [dropdownOpen, setDropdownOpen] = useState(false)
  const [searchFilter, setSearchFilter] = useState('')
  const dropdownRef = useRef<HTMLDivElement>(null)
  const searchInputRef = useRef<HTMLInputElement>(null)

  // Load branches
  const loadBranches = useCallback(async () => {
    if (!worktreePath) return
    setIsLoadingBranches(true)
    try {
      const result = await window.gitOps.listBranchesWithStatus(worktreePath)
      if (result.success && result.branches) {
        setBranches(result.branches)
      }
    } catch (error) {
      console.error('Failed to load branches:', error)
    } finally {
      setIsLoadingBranches(false)
    }
  }, [worktreePath])

  // Load diff files for selected branch
  const loadDiffFiles = useCallback(async () => {
    if (!worktreePath || !selectedBranch) {
      setFiles([])
      return
    }
    setIsLoadingFiles(true)
    try {
      const result = await window.gitOps.getBranchDiffFiles(worktreePath, selectedBranch)
      if (result.success && result.files) {
        setFiles(result.files)
        setDiffError(null)
      } else {
        setFiles([])
        setDiffError(result.error || t('fileTree.branchDiff.loadError'))
      }
    } catch (error) {
      console.error('Failed to load branch diff files:', error)
      setFiles([])
      setDiffError(error instanceof Error ? error.message : t('fileTree.branchDiff.loadError'))
    } finally {
      setIsLoadingFiles(false)
    }
  }, [worktreePath, selectedBranch, t])

  // Initial load of branches
  useEffect(() => {
    loadBranches()
  }, [loadBranches])

  // Load files when selected branch changes
  useEffect(() => {
    loadDiffFiles()
  }, [loadDiffFiles])

  // Listen for git status changes to auto-refresh file list
  useEffect(() => {
    if (!worktreePath || !selectedBranch) return
    const cleanup = window.gitOps.onStatusChanged((event) => {
      if (event.worktreePath === worktreePath) {
        loadDiffFiles()
      }
    })
    return cleanup
  }, [worktreePath, selectedBranch, loadDiffFiles])

  // Close dropdown on outside click
  useEffect(() => {
    if (!dropdownOpen) return
    function handleClickOutside(e: MouseEvent): void {
      if (dropdownRef.current && !dropdownRef.current.contains(e.target as Node)) {
        setDropdownOpen(false)
        setSearchFilter('')
      }
    }
    document.addEventListener('mousedown', handleClickOutside)
    return () => document.removeEventListener('mousedown', handleClickOutside)
  }, [dropdownOpen])

  // Focus search when dropdown opens
  useEffect(() => {
    if (dropdownOpen && searchInputRef.current) {
      searchInputRef.current.focus()
    }
  }, [dropdownOpen])

  const handleSelectBranch = useCallback(
    (branch: string) => {
      if (!worktreePath) return
      setSelectedDiffBranch(worktreePath, branch)
      setDropdownOpen(false)
      setSearchFilter('')
    },
    [worktreePath, setSelectedDiffBranch]
  )

  const handleFileClick = useCallback(
    (file: BranchDiffFile) => {
      if (!worktreePath || !selectedBranch) return
      const fileName = file.relativePath.split('/').pop() || file.relativePath
      useFileViewerStore.getState().setActiveDiff({
        worktreePath,
        worktreeId: selectedWorktreeId ?? undefined,
        filePath: file.relativePath,
        fileName,
        staged: false,
        isUntracked: false,
        compareBranch: selectedBranch
      })
    },
    [worktreePath, selectedBranch, selectedWorktreeId]
  )

  const handleRefresh = useCallback(async () => {
    await Promise.all([loadBranches(), loadDiffFiles()])
  }, [loadBranches, loadDiffFiles])

  // Split branches into local-first, remote-second, filtered by search
  const filteredBranches = useMemo(() => {
    const lower = searchFilter.toLowerCase()
    const filtered = branches.filter((b) => b.name.toLowerCase().includes(lower))
    const local = filtered.filter((b) => !b.isRemote)
    const remote = filtered.filter((b) => b.isRemote)
    return { local, remote }
  }, [branches, searchFilter])

  if (!worktreePath) {
    return (
      <div className="p-4 text-sm text-muted-foreground text-center">
        {t('fileTree.branchDiff.noWorktree')}
      </div>
    )
  }

  return (
    <div className="flex flex-col h-full" data-testid="branch-diff-view">
      {/* Branch selector */}
      <div
        className="relative border-b border-border/60 bg-background/62 px-3 py-2"
        ref={dropdownRef}
      >
        <button
          type="button"
          className={cn(
            'flex w-full items-center gap-1.5 rounded-lg border border-border/70 bg-background px-2.5 py-1.5 text-xs transition-colors hover:bg-sidebar-accent/30'
          )}
          onClick={() => setDropdownOpen((prev) => !prev)}
          disabled={isLoadingBranches}
        >
          <GitBranch className="h-3 w-3 text-muted-foreground shrink-0" />
          <span className="truncate flex-1 text-left">
            {selectedBranch || t('fileTree.branchDiff.selectBranch')}
          </span>
          <ChevronDown
            className={cn(
              'h-3 w-3 text-muted-foreground shrink-0 transition-transform',
              dropdownOpen && 'rotate-180'
            )}
          />
        </button>

        {dropdownOpen && (
          <div className="absolute left-0 right-0 z-50 mx-3 mt-2 flex max-h-64 flex-col rounded-xl border border-border bg-popover shadow-lg">
            {/* Search input */}
            <div className="flex items-center gap-1.5 border-b border-border/60 px-2 py-1.5">
              <Search className="h-3 w-3 text-muted-foreground shrink-0" />
              <input
                ref={searchInputRef}
                type="text"
                className="flex-1 bg-transparent text-xs outline-none placeholder:text-muted-foreground"
                placeholder={t('fileTree.branchDiff.filterBranches')}
                value={searchFilter}
                onChange={(e) => setSearchFilter(e.target.value)}
              />
            </div>

            {/* Branch list */}
            <div className="overflow-y-auto flex-1">
              {filteredBranches.local.length > 0 && (
                <div>
                  <div className="px-2 py-1 text-[10px] font-medium text-muted-foreground uppercase tracking-wider">
                    {t('fileTree.branchDiff.local')}
                  </div>
                  {filteredBranches.local.map((branch) => (
                    <button
                      key={branch.name}
                      type="button"
                      className={cn(
                        'flex items-center gap-1.5 w-full px-2 py-1 text-xs hover:bg-sidebar-accent/50',
                        branch.name === selectedBranch && 'bg-sidebar-accent text-sidebar-accent-foreground'
                      )}
                      onClick={() => handleSelectBranch(branch.name)}
                    >
                      <span className="truncate">{branch.name}</span>
                      {branch.isCheckedOut && (
                        <span className="text-[10px] text-muted-foreground ml-auto shrink-0">
                          {t('fileTree.branchDiff.current')}
                        </span>
                      )}
                    </button>
                  ))}
                </div>
              )}

              {filteredBranches.remote.length > 0 && (
                <div>
                  <div className="px-2 py-1 text-[10px] font-medium text-muted-foreground uppercase tracking-wider">
                    {t('fileTree.branchDiff.remote')}
                  </div>
                  {filteredBranches.remote.map((branch) => (
                    <button
                      key={branch.name}
                      type="button"
                      className={cn(
                        'flex items-center gap-1.5 w-full px-2 py-1 text-xs hover:bg-sidebar-accent/50',
                        branch.name === selectedBranch && 'bg-sidebar-accent text-sidebar-accent-foreground'
                      )}
                      onClick={() => handleSelectBranch(branch.name)}
                    >
                      <span className="truncate">{branch.name}</span>
                    </button>
                  ))}
                </div>
              )}

              {filteredBranches.local.length === 0 && filteredBranches.remote.length === 0 && (
                <div className="px-2 py-3 text-xs text-muted-foreground text-center">
                  {t('fileTree.branchDiff.noBranches')}
                </div>
              )}
            </div>
          </div>
        )}
      </div>

      {/* File list */}
      {!selectedBranch ? (
        <div className="flex-1 flex items-center justify-center text-xs text-muted-foreground">
          {t('fileTree.branchDiff.selectBranchToSeeDifferences')}
        </div>
      ) : isLoadingFiles ? (
        <div className="flex-1 flex items-center justify-center text-xs text-muted-foreground">
          {t('fileTree.branchDiff.loading')}
        </div>
      ) : diffError ? (
        <div className="flex-1 flex items-center justify-center text-xs text-destructive px-4 text-center">
          {diffError}
        </div>
      ) : files.length === 0 ? (
        <div className="flex-1 flex items-center justify-center text-xs text-muted-foreground">
          {t('fileTree.branchDiff.noDifferences')}
        </div>
      ) : (
        <div className="flex-1 overflow-y-auto">
          {files.map((file) => {
            const fileName = file.relativePath.split('/').pop() || file.relativePath
            const ext = fileName.includes('.') ? '.' + fileName.split('.').pop() : null

            return (
              <div
                key={file.relativePath}
                className="flex items-center gap-1.5 px-2 py-0.5 hover:bg-sidebar-accent/30 cursor-pointer"
                onClick={() => handleFileClick(file)}
                data-testid={`branch-diff-file-${file.relativePath}`}
              >
                <FileIcon
                  name={fileName}
                  extension={ext}
                  isDirectory={false}
                  className="h-3.5 w-3.5"
                />
                <span className="text-xs truncate flex-1" title={file.relativePath}>
                  {file.relativePath}
                </span>
                <GitStatusIndicator status={toGitStatusCode(file.status)} className="mr-1" />
              </div>
            )
          })}
        </div>
      )}

      {/* Status bar */}
      <div className="flex items-center justify-between border-t border-border/60 bg-background/62 px-3 py-2">
        <span className="text-[10px] text-muted-foreground">
          {selectedBranch
            ? t('fileTree.branchDiff.changedCount', {
                count: files.length,
                label:
                  files.length === 1
                    ? t('fileTree.branchDiff.fileSingular')
                    : t('fileTree.branchDiff.filePlural')
              })
            : t('fileTree.branchDiff.noBranchSelected')}
        </span>
        <button
          className={cn(
            'rounded-md border border-transparent p-1 text-muted-foreground transition-colors hover:border-border/70 hover:bg-background hover:text-foreground',
            isLoadingFiles && 'animate-spin'
          )}
          onClick={handleRefresh}
          disabled={isLoadingFiles}
          title={t('fileTree.branchDiff.refresh')}
        >
          <RefreshCw className="h-3 w-3" />
        </button>
      </div>
    </div>
  )
}
