/**
 * Mail folder tree sidebar component.
 * Shows accounts as top-level nodes with their folders nested underneath.
 * Folders come as a flat list with parent_id and are built into a tree.
 *
 * Styling matches the AI assistant SessionList tree: compact font, tight spacing,
 * right-click context menu with "Ordner leeren".
 */

import React, { useState, useMemo, useEffect, useRef, useCallback } from 'react';
import clsx from 'clsx';
import { useTranslation } from 'react-i18next';
import type { MailAccount, MailFolder } from '@/api/mail';
import { emptyFolder } from '@/api/mail';
import { Badge } from '@/components/ui/Badge';
import { EmptyState } from '@/components/ui/EmptyState';
import { ChevronRight, Folder, Loader2 } from 'lucide-react';

/**
 * Map IMAP folder names to German display names.
 */
const FOLDER_NAME_MAP: Record<string, string> = {
  INBOX: 'Posteingang',
  'INBOX.Sent': 'Gesendet',
  'INBOX.Drafts': 'Entwürfe',
  'INBOX.Trash': 'Papierkorb',
  'INBOX.Archive': 'Archiv',
  'INBOX.spam': 'Spam',
  'INBOX.Spam': 'Spam',
  Sent: 'Gesendet',
  Drafts: 'Entwürfe',
  Spam: 'Spam',
  Junk: 'Spam',
  Trash: 'Papierkorb',
  'Sent Items': 'Gesendet',
  'Sent Mail': 'Gesendet',
  Draft: 'Entwürfe',
  Deleted: 'Papierkorb',
  'Deleted Items': 'Papierkorb',
  'Junk Email': 'Spam',
  'Junk E-mail': 'Spam',
  Archive: 'Archiv',
};

/**
 * Get the display name for a folder — uses the German name from the map
 * if the imap_name matches a known folder, otherwise uses the stored name.
 */
function getFolderDisplayName(folder: MailFolder): string {
  if (folder.imap_name && FOLDER_NAME_MAP[folder.imap_name]) {
    return FOLDER_NAME_MAP[folder.imap_name];
  }
  return folder.name;
}

export interface MailFolderTreeProps {
  accounts: MailAccount[];
  folders: MailFolder[];
  selectedFolderId: string | null;
  onSelect: (folderId: string) => void;
  loading: boolean;
  onFolderEmptied?: () => void;
}

/**
 * Build a hierarchical tree from a flat folder list for a given account.
 */
function buildFolderTree(folders: MailFolder[], accountId: string): MailFolder[] {
  const accountFolders = folders.filter((f) => f.account_id === accountId);
  const byId = new Map<string, MailFolder & { children: MailFolder[] }>();

  for (const f of accountFolders) {
    byId.set(f.id, { ...f, children: [] });
  }

  const roots: MailFolder[] = [];

  for (const f of accountFolders) {
    const node = byId.get(f.id)!;
    if (f.parent_id && byId.has(f.parent_id)) {
      byId.get(f.parent_id)!.children.push(node);
    } else {
      roots.push(node);
    }
  }

  return roots;
}

function ChevronIcon({ expanded }: { expanded: boolean }) {
  return (
    <ChevronRight className={clsx('w-4 h-4 transition-transform flex-shrink-0', expanded && 'rotate-90')} aria-hidden="true" strokeWidth={2} />
  );
}

function FolderIcon() {
  return (
    <Folder className="w-4 h-4 text-secondary-400 flex-shrink-0" aria-hidden="true" strokeWidth={2} />
  );
}

interface ContextMenuState {
  x: number;
  y: number;
  folderId: string;
  folderName: string;
}

function ContextMenu({
  state,
  onClose,
  onEmptyFolder,
}: {
  state: ContextMenuState;
  onClose: () => void;
  onEmptyFolder: (folderId: string, folderName: string) => void;
}) {
  const ref = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const handler = (e: MouseEvent) => {
      if (ref.current && !ref.current.contains(e.target as Node)) onClose();
    };
    document.addEventListener('mousedown', handler);
    return () => document.removeEventListener('mousedown', handler);
  }, [onClose]);

  return (
    <div
      ref={ref}
      className="fixed z-50 bg-white border border-secondary-200 rounded-lg shadow-lg py-1 min-w-[160px]"
      style={{ left: state.x, top: state.y }}
    >
      <button
        onClick={() => { onEmptyFolder(state.folderId, state.folderName); onClose(); }}
        className="w-full text-left px-3 py-1.5 text-sm text-red-600 hover:bg-red-50"
      >
        Ordner leeren
      </button>
    </div>
  );
}

function FolderNode({
  folder,
  selectedFolderId,
  onSelect,
  depth,
  onContextMenu,
}: {
  folder: MailFolder;
  selectedFolderId: string | null;
  onSelect: (folderId: string) => void;
  depth: number;
  onContextMenu: (e: React.MouseEvent, folder: MailFolder) => void;
}) {
  const [expanded, setExpanded] = useState(true);
  const isSelected = folder.id === selectedFolderId;
  const hasChildren = folder.children && folder.children.length > 0;

  return (
    <div role="treeitem" aria-selected={isSelected} aria-label={getFolderDisplayName(folder)}>
      <div
        className="flex items-center"
        style={{ paddingLeft: `${depth * 12 + 8}px` }}
      >
        {hasChildren ? (
          <button
            onClick={(e) => {
              e.stopPropagation();
              setExpanded(!expanded);
            }}
            className="flex-shrink-0 p-0.5 hover:bg-secondary-100 rounded"
            aria-label={expanded ? 'Collapse' : 'Expand'}
            data-testid={`folder-chevron-${folder.id}`}
          >
            <ChevronIcon expanded={expanded} />
          </button>
        ) : (
          <span className="w-4 flex-shrink-0" />
        )}
        <button
          onClick={() => onSelect(folder.id)}
          onContextMenu={(e) => onContextMenu(e, folder)}
          className={clsx(
            'group flex-1 flex items-center gap-1 px-2 py-1.5 rounded-md text-sm cursor-pointer',
            'motion-safe:transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500',
            isSelected
              ? 'bg-primary-50 text-primary-700 font-medium'
              : 'hover:bg-secondary-100 text-secondary-700',
          )}
          data-testid={`folder-${folder.id}`}
        >
          <FolderIcon />
          <span className="flex-1 truncate text-left">{getFolderDisplayName(folder)}</span>
          {folder.unread_count > 0 && (
            <Badge variant="primary" className="text-xs">{folder.unread_count}</Badge>
          )}
          {folder.total_count > 0 && folder.unread_count === 0 && (
            <span className="text-xs text-secondary-400">{folder.total_count}</span>
          )}
        </button>
      </div>
      {hasChildren && expanded && (
        <div role="group">
          {folder.children!.map((child) => (
            <FolderNode
              key={child.id}
              folder={child}
              selectedFolderId={selectedFolderId}
              onSelect={onSelect}
              depth={depth + 1}
              onContextMenu={onContextMenu}
            />
          ))}
        </div>
      )}
    </div>
  );
}

function AccountNode({
  account,
  folders,
  selectedFolderId,
  onSelect,
  onContextMenu,
}: {
  account: MailAccount;
  folders: MailFolder[];
  selectedFolderId: string | null;
  onSelect: (folderId: string) => void;
  onContextMenu: (e: React.MouseEvent, folder: MailFolder) => void;
}) {
  const [expanded, setExpanded] = useState(true);
  const accountFolders = useMemo(
    () => buildFolderTree(folders, account.id),
    [folders, account.id],
  );

  return (
    <div role="treeitem" aria-label={account.email}>
      <button
        onClick={() => setExpanded(!expanded)}
        className="w-full flex items-center gap-1 px-2 py-1.5 rounded-md text-sm font-medium text-secondary-700 hover:bg-secondary-100"
        data-testid={`account-${account.id}`}
      >
        <ChevronIcon expanded={expanded} />
        <span className="flex-1 truncate text-left">{account.display_name || account.email}</span>
      </button>
      {expanded && (
        <div role="group">
          {accountFolders.map((folder) => (
            <FolderNode
              key={folder.id}
              folder={folder}
              selectedFolderId={selectedFolderId}
              onSelect={onSelect}
              depth={0}
              onContextMenu={onContextMenu}
            />
          ))}
        </div>
      )}
    </div>
  );
}

export function MailFolderTree({ accounts, folders, selectedFolderId, onSelect, loading, onFolderEmptied }: MailFolderTreeProps) {
  const { t } = useTranslation();
  const [contextMenu, setContextMenu] = useState<ContextMenuState | null>(null);

  const handleContextMenu = useCallback((e: React.MouseEvent, folder: MailFolder) => {
    e.preventDefault();
    e.stopPropagation();
    setContextMenu({
      x: e.clientX,
      y: e.clientY,
      folderId: folder.id,
      folderName: getFolderDisplayName(folder),
    });
  }, []);

  const handleEmptyFolder = useCallback(async (folderId: string, folderName: string) => {
    if (!confirm(`Ordner "${folderName}" wirklich leeren? Alle E-Mails werden gelöscht.`)) return;
    try {
      const result = await emptyFolder(folderId);
      if (onFolderEmptied) onFolderEmptied();
    } catch (e) {
      console.error('Failed to empty folder:', e);
      alert('Fehler beim Leeren des Ordners: ' + (e instanceof Error ? e.message : String(e)));
    }
  }, [onFolderEmptied]);

  if (loading) {
    return (
      <div className="flex items-center justify-center py-8" data-testid="folder-tree-loading">
        <Loader2 className="animate-spin h-5 w-5 text-secondary-400" aria-hidden="true" />
        <span className="ml-2 text-sm text-secondary-500">{t('common.loading')}</span>
      </div>
    );
  }

  if (accounts.length === 0) {
    return (
      <EmptyState
        title={t('mail.noFolders')}
        description={t('mail.noFoldersDesc')}
        data-testid="folder-tree-empty"
      />
    );
  }

  return (
    <>
      <div className="flex flex-col" role="tree" data-testid="folder-tree-list">
        {accounts.map((account) => (
          <AccountNode
            key={account.id}
            account={account}
            folders={folders}
            selectedFolderId={selectedFolderId}
            onSelect={onSelect}
            onContextMenu={handleContextMenu}
          />
        ))}
      </div>
      {contextMenu && (
        <ContextMenu
          state={contextMenu}
          onClose={() => setContextMenu(null)}
          onEmptyFolder={handleEmptyFolder}
        />
      )}
    </>
  );
}
