import { useState, useEffect, useRef, useMemo, useCallback } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import { Modal, Typography, Grid, Spin, Tag, theme, type GlobalToken } from 'antd';
import {
  SearchOutlined,
  DashboardOutlined,
  SendOutlined,
  IdcardOutlined,
  MailOutlined,
  MessageOutlined,
  EnvironmentOutlined,
  TeamOutlined,
  SettingOutlined,
  CalendarOutlined,
  ScheduleOutlined,
  FileTextOutlined,
  BookOutlined,
  GlobalOutlined,
  CodeOutlined,
  DatabaseOutlined,
  ApiOutlined,
  BranchesOutlined,
  CloudServerOutlined,
  QrcodeOutlined,
  PlaySquareOutlined,
  FolderOutlined,
  HistoryOutlined,
  LineChartOutlined,
  BarChartOutlined,
  EditOutlined,
  OrderedListOutlined,
  DollarOutlined,
  ShoppingOutlined,
  HeartOutlined,
  CrownOutlined,
  PictureOutlined,
  LockOutlined,
  PhoneOutlined,
  TagOutlined,
  ThunderboltOutlined,
  UserOutlined,
  FileMarkdownOutlined,
  ContactsOutlined,
  ScissorOutlined,
  StarFilled,
} from '@ant-design/icons';
import { useCommandPaletteStore } from '@/stores/command-palette.store';
import { useAuthStore } from '@/stores/auth.store';
import { useFavoritesStore } from '@/stores/favorites.store';
import { useCommandIndex } from './useCommandIndex';
import { useEntitySearch } from './useEntitySearch';
import { parseQuery, SCOPE_DEFINITIONS } from './scopeFilter';
import type { CommandItem, EntityResult, CommandCategory } from './types';

const { Text } = Typography;
const { useBreakpoint } = Grid;

/** Map icon string IDs to Ant Design components */
const ICON_MAP: Record<string, React.ReactNode> = {
  DashboardOutlined: <DashboardOutlined />,
  SendOutlined: <SendOutlined />,
  IdcardOutlined: <IdcardOutlined />,
  MailOutlined: <MailOutlined />,
  MessageOutlined: <MessageOutlined />,
  EnvironmentOutlined: <EnvironmentOutlined />,
  TeamOutlined: <TeamOutlined />,
  SettingOutlined: <SettingOutlined />,
  CalendarOutlined: <CalendarOutlined />,
  ScheduleOutlined: <ScheduleOutlined />,
  FileTextOutlined: <FileTextOutlined />,
  BookOutlined: <BookOutlined />,
  GlobalOutlined: <GlobalOutlined />,
  CodeOutlined: <CodeOutlined />,
  DatabaseOutlined: <DatabaseOutlined />,
  ApiOutlined: <ApiOutlined />,
  BranchesOutlined: <BranchesOutlined />,
  CloudServerOutlined: <CloudServerOutlined />,
  QrcodeOutlined: <QrcodeOutlined />,
  PlaySquareOutlined: <PlaySquareOutlined />,
  FolderOutlined: <FolderOutlined />,
  HistoryOutlined: <HistoryOutlined />,
  LineChartOutlined: <LineChartOutlined />,
  BarChartOutlined: <BarChartOutlined />,
  EditOutlined: <EditOutlined />,
  OrderedListOutlined: <OrderedListOutlined />,
  DollarOutlined: <DollarOutlined />,
  ShoppingOutlined: <ShoppingOutlined />,
  HeartOutlined: <HeartOutlined />,
  CrownOutlined: <CrownOutlined />,
  PictureOutlined: <PictureOutlined />,
  LockOutlined: <LockOutlined />,
  PhoneOutlined: <PhoneOutlined />,
  TagOutlined: <TagOutlined />,
  FileMarkdownOutlined: <FileMarkdownOutlined />,
  UserOutlined: <UserOutlined />,
  ContactsOutlined: <ContactsOutlined />,
  ScissorOutlined: <ScissorOutlined />,
};

const CATEGORY_LABELS: Record<CommandCategory, string> = {
  navigation: 'Pages',
  settings: 'Settings',
  action: 'Actions',
};

/** A unified item type for the flattened result list */
type FlatItem =
  | { type: 'command'; item: CommandItem }
  | { type: 'entity'; item: EntityResult };

export default function CommandPalette() {
  const { isOpen, close, recentItems, addRecent } = useCommandPaletteStore();
  const { isAuthenticated } = useAuthStore();
  const { favorites } = useFavoritesStore();
  const location = useLocation();
  const navigate = useNavigate();
  const { token } = theme.useToken();
  const screens = useBreakpoint();
  const isMobile = !screens.md;

  const [query, setQuery] = useState('');
  const [selectedIndex, setSelectedIndex] = useState(0);
  const inputRef = useRef<HTMLInputElement>(null);
  const listRef = useRef<HTMLDivElement>(null);

  // Parse query for scope prefix
  const parsed = useMemo(() => parseQuery(query), [query]);

  const { search, allItems } = useCommandIndex();
  const { results: entityResults, loading: entityLoading } = useEntitySearch(
    parsed.strippedQuery,
    parsed.scope?.entityTypes,
  );

  // Only render inside admin panel
  const isAdminRoute = location.pathname.startsWith('/app');
  const shouldRender = isAuthenticated && isAdminRoute;

  // Global Cmd+K / Ctrl+K listener
  useEffect(() => {
    if (!shouldRender) return;
    const handler = (e: KeyboardEvent) => {
      if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
        e.preventDefault();
        useCommandPaletteStore.getState().toggle();
      }
    };
    document.addEventListener('keydown', handler);
    return () => document.removeEventListener('keydown', handler);
  }, [shouldRender]);

  // Reset state when opening
  useEffect(() => {
    if (isOpen) {
      setQuery('');
      setSelectedIndex(0);
    }
  }, [isOpen]);

  // Focus input after modal open animation completes
  const handleAfterOpenChange = useCallback((open: boolean) => {
    if (open) {
      inputRef.current?.focus();
    }
  }, []);

  // Build command results from search
  const commandResults = useMemo(() => {
    if (!parsed.strippedQuery && !parsed.scope) return [];
    // If scope is active but query is empty, show all items in that scope's groups
    if (parsed.scope && !parsed.strippedQuery) {
      return allItems.filter((item) => parsed.scope!.groups.includes(item.group));
    }
    return search(parsed.strippedQuery, parsed.scope?.groups);
  }, [parsed, search, allItems]);

  // Build favorite items (when no query)
  const favoriteCommandItems = useMemo(() => {
    if (query) return [];
    const favoriteSet = new Set(favorites);
    return allItems.filter((item) => favoriteSet.has(item.path));
  }, [query, favorites, allItems]);

  // Set of favorited paths for badge rendering
  const favoritePaths = useMemo(() => new Set(favorites), [favorites]);

  // Build recent items list (when no query), excluding favorites
  const recentCommandItems = useMemo(() => {
    if (query) return [];
    const favIds = new Set(favoriteCommandItems.map((i) => i.id));
    return recentItems
      .map((id) => allItems.find((item) => item.id === id))
      .filter((item): item is CommandItem => !!item && !favIds.has(item.id));
  }, [query, recentItems, allItems, favoriteCommandItems]);

  // Flatten all results into a single list for keyboard navigation.
  // Order: Favorites → Recent → Pages → Entities → Actions → Settings
  const flatList = useMemo((): FlatItem[] => {
    const items: FlatItem[] = [];
    if (!query) {
      for (const item of favoriteCommandItems) {
        items.push({ type: 'command', item });
      }
      for (const item of recentCommandItems) {
        items.push({ type: 'command', item });
      }
    } else if (parsed.showScopeList) {
      // No items when showing scope selector
    } else {
      const pages = commandResults.filter((i) => i.category === 'navigation');
      const actions = commandResults.filter((i) => i.category === 'action');
      const settings = commandResults.filter((i) => i.category === 'settings');
      // Pages first (exact name matches ranked highest by MiniSearch)
      for (const item of pages) items.push({ type: 'command', item });
      // Entities next (database records like doc files, campaigns, users)
      for (const item of entityResults) items.push({ type: 'entity', item });
      // Actions after entities
      for (const item of actions) items.push({ type: 'command', item });
      // Settings last
      for (const item of settings) items.push({ type: 'command', item });
    }
    return items;
  }, [query, favoriteCommandItems, recentCommandItems, parsed.showScopeList, commandResults, entityResults]);

  // Clamp selected index
  useEffect(() => {
    setSelectedIndex((prev) => Math.min(prev, Math.max(0, flatList.length - 1)));
  }, [flatList.length]);

  // Scroll selected item into view
  useEffect(() => {
    const container = listRef.current;
    if (!container) return;
    const el = container.querySelector(`[data-index="${selectedIndex}"]`);
    el?.scrollIntoView({ block: 'nearest' });
  }, [selectedIndex]);

  const handleSelect = useCallback(
    (flatItem: FlatItem) => {
      if (flatItem.type === 'command') {
        const cmd = flatItem.item;
        addRecent(cmd.id);
        // Special handling for non-navigation actions
        if (cmd.id === 'action-learning-tours') {
          import('@/stores/tour.store').then(({ useTourStore }) => useTourStore.getState().openHub());
        } else {
          navigate(cmd.path, { state: cmd.navigationState });
        }
      } else {
        navigate(flatItem.item.path, { state: flatItem.item.navigationState });
      }
      close();
    },
    [navigate, close, addRecent],
  );

  const handleKeyDown = useCallback(
    (e: React.KeyboardEvent) => {
      if (e.key === 'ArrowDown') {
        e.preventDefault();
        setSelectedIndex((prev) => Math.min(prev + 1, flatList.length - 1));
      } else if (e.key === 'ArrowUp') {
        e.preventDefault();
        setSelectedIndex((prev) => Math.max(prev - 1, 0));
      } else if (e.key === 'Enter') {
        e.preventDefault();
        if (flatList[selectedIndex]) {
          handleSelect(flatList[selectedIndex]);
        }
      }
    },
    [flatList, selectedIndex, handleSelect],
  );

  // Group commands by category for display, in priority order:
  // Pages (navigation) → Actions → Settings (least frequent)
  // Entities are interleaved between pages and actions in the render phase.
  // NOTE: These hooks must stay above the early return to satisfy Rules of Hooks
  const CATEGORY_ORDER: (CommandCategory | 'favorites' | 'recent')[] = [
    'favorites', 'recent', 'navigation', 'action', 'settings',
  ];

  const groupedCommands = useMemo(() => {
    const unordered = new Map<string, CommandItem[]>();

    if (!query) {
      // No-query mode: favorites then recents
      if (favoriteCommandItems.length > 0) {
        unordered.set('favorites', favoriteCommandItems);
      }
      if (recentCommandItems.length > 0) {
        unordered.set('recent', recentCommandItems);
      }
    } else if (!parsed.showScopeList) {
      for (const item of commandResults) {
        const key = item.category;
        if (!unordered.has(key)) unordered.set(key, []);
        unordered.get(key)!.push(item);
      }
    }

    // Re-insert in priority order
    const ordered = new Map<string, CommandItem[]>();
    for (const key of CATEGORY_ORDER) {
      if (unordered.has(key)) ordered.set(key, unordered.get(key)!);
    }
    return ordered;
  }, [query, parsed.showScopeList, commandResults, favoriteCommandItems, recentCommandItems]);

  // Group entities by type
  const groupedEntities = useMemo(() => {
    const groups = new Map<string, EntityResult[]>();
    for (const item of entityResults) {
      if (!groups.has(item.entityType)) groups.set(item.entityType, []);
      groups.get(item.entityType)!.push(item);
    }
    return groups;
  }, [entityResults]);

  if (!shouldRender) return null;

  // Get flat index for a given item
  let flatIndex = 0;

  const isMac = navigator.platform?.toLowerCase().includes('mac');

  // Dynamic placeholder
  const placeholder = parsed.scope
    ? `Search ${parsed.scope.label.toLowerCase()}...`
    : 'Search pages, settings, data...';

  return (
    <Modal
      open={isOpen}
      onCancel={close}
      afterOpenChange={handleAfterOpenChange}
      footer={null}
      closable={false}
      width={isMobile ? '100%' : 560}
      centered
      destroyOnClose
      styles={{
        content: {
          padding: 0,
          overflow: 'hidden',
          background: token.colorBgElevated,
          borderRadius: token.borderRadiusLG,
        },
        mask: { backdropFilter: 'blur(4px)' },
      }}
    >
      <div onKeyDown={handleKeyDown}>
        {/* Search input */}
        <div
          style={{
            padding: '12px 16px',
            borderBottom: `1px solid ${token.colorBorderSecondary}`,
            display: 'flex',
            alignItems: 'center',
            gap: 8,
          }}
        >
          <SearchOutlined style={{ color: token.colorTextSecondary, fontSize: 16 }} />
          {parsed.scope && (
            <Tag
              color={token.colorPrimary}
              style={{ margin: 0, fontSize: 11, lineHeight: '18px', padding: '0 6px' }}
              closable
              onClose={() => setQuery(parsed.strippedQuery)}
            >
              {parsed.scope.label}
            </Tag>
          )}
          <input
            ref={inputRef}
            value={query}
            onChange={(e) => {
              setQuery(e.target.value);
              setSelectedIndex(0);
            }}
            placeholder={placeholder}
            style={{
              flex: 1,
              border: 'none',
              outline: 'none',
              background: 'transparent',
              color: token.colorText,
              fontSize: 15,
            }}
            autoFocus
          />
          {entityLoading && <Spin size="small" />}
        </div>

        {/* Results list — fixed height keeps search bar anchored */}
        <div
          ref={listRef}
          style={{
            height: 400,
            overflowY: 'auto',
            padding: '4px 0',
          }}
        >
          {/* Scope selector (when user types bare @) */}
          {parsed.showScopeList && (
            <div>
              <div
                style={{
                  padding: '8px 16px 4px',
                  fontSize: 11,
                  fontWeight: 600,
                  textTransform: 'uppercase',
                  letterSpacing: '0.05em',
                  color: token.colorTextSecondary,
                }}
              >
                Filter by scope
              </div>
              {SCOPE_DEFINITIONS.map((scope) => (
                <div
                  key={scope.prefix}
                  onClick={() => {
                    setQuery(`@${scope.prefix}:`);
                    setSelectedIndex(0);
                    inputRef.current?.focus();
                  }}
                  style={{
                    padding: '8px 16px',
                    display: 'flex',
                    alignItems: 'center',
                    gap: 10,
                    cursor: 'pointer',
                    borderRadius: 4,
                    margin: '0 4px',
                    transition: 'background 0.1s',
                  }}
                  onMouseEnter={(e) => {
                    (e.currentTarget as HTMLDivElement).style.background = token.colorPrimaryBg;
                  }}
                  onMouseLeave={(e) => {
                    (e.currentTarget as HTMLDivElement).style.background = 'transparent';
                  }}
                >
                  <span
                    style={{
                      fontFamily: 'monospace',
                      fontSize: 13,
                      color: token.colorPrimary,
                      width: 90,
                      flexShrink: 0,
                    }}
                  >
                    @{scope.prefix}:
                  </span>
                  <span style={{ color: token.colorText, fontSize: 14 }}>{scope.label}</span>
                </div>
              ))}
            </div>
          )}

          {/* Render in priority order: Pages → Entities → Actions → Settings
              For no-query mode: Favorites → Recent (no entities) */}
          {(() => {
            const sections: React.ReactNode[] = [];
            const commandEntries = Array.from(groupedCommands.entries());

            // Pages (navigation) first — skip actions and settings for now
            for (const [groupKey, items] of commandEntries) {
              if (groupKey === 'settings' || groupKey === 'action') continue;
              sections.push(
                <CommandGroupSection
                  key={groupKey}
                  groupKey={groupKey}
                  items={items}
                  flatIndexRef={{ current: flatIndex }}
                  selectedIndex={selectedIndex}
                  favoritePaths={favoritePaths}
                  token={token}
                  onSelect={handleSelect}
                  onHover={setSelectedIndex}
                />,
              );
              flatIndex += items.length;
            }

            // Entities right after pages (doc files, campaigns, users, etc.)
            if (query && !parsed.showScopeList) {
              for (const [entityType, items] of groupedEntities.entries()) {
                sections.push(
                  <EntityGroupSection
                    key={entityType}
                    entityType={entityType}
                    items={items}
                    flatIndexRef={{ current: flatIndex }}
                    selectedIndex={selectedIndex}
                    token={token}
                    onSelect={handleSelect}
                    onHover={setSelectedIndex}
                  />,
                );
                flatIndex += items.length;
              }
            }

            // Actions after entities
            const actionItems = groupedCommands.get('action');
            if (actionItems) {
              sections.push(
                <CommandGroupSection
                  key="action"
                  groupKey="action"
                  items={actionItems}
                  flatIndexRef={{ current: flatIndex }}
                  selectedIndex={selectedIndex}
                  favoritePaths={favoritePaths}
                  token={token}
                  onSelect={handleSelect}
                  onHover={setSelectedIndex}
                />,
              );
              flatIndex += actionItems.length;
            }

            // Settings last
            const settingsItems = groupedCommands.get('settings');
            if (settingsItems) {
              sections.push(
                <CommandGroupSection
                  key="settings"
                  groupKey="settings"
                  items={settingsItems}
                  flatIndexRef={{ current: flatIndex }}
                  selectedIndex={selectedIndex}
                  favoritePaths={favoritePaths}
                  token={token}
                  onSelect={handleSelect}
                  onHover={setSelectedIndex}
                />,
              );
              flatIndex += settingsItems.length;
            }

            return sections;
          })()}

          {/* Empty state */}
          {flatList.length === 0 && !entityLoading && query && !parsed.showScopeList && (
            <div style={{ padding: '24px 16px', textAlign: 'center' }}>
              <Text type="secondary">No results for "{parsed.strippedQuery || query}"</Text>
            </div>
          )}

          {/* No query, no recents, no favorites */}
          {flatList.length === 0 && !query && (
            <div style={{ padding: '24px 16px', textAlign: 'center' }}>
              <Text type="secondary">Type to search pages, settings, and data</Text>
            </div>
          )}
        </div>

        {/* Footer hints */}
        <div
          style={{
            padding: '6px 16px',
            borderTop: `1px solid ${token.colorBorderSecondary}`,
            display: 'flex',
            gap: 16,
            fontSize: 12,
            color: token.colorTextTertiary,
            flexWrap: 'wrap',
          }}
        >
          <span><kbd style={kbdStyle(token)}>↑↓</kbd> navigate</span>
          <span><kbd style={kbdStyle(token)}>↵</kbd> open</span>
          <span><kbd style={kbdStyle(token)}>esc</kbd> close</span>
          <span><kbd style={kbdStyle(token)}>@</kbd> scope</span>
          <span style={{ marginLeft: 'auto' }}>
            <kbd style={kbdStyle(token)}>{isMac ? '⌘' : 'Ctrl'}</kbd>+<kbd style={kbdStyle(token)}>K</kbd>
          </span>
        </div>
      </div>
    </Modal>
  );
}

function kbdStyle(token: GlobalToken): React.CSSProperties {
  return {
    display: 'inline-block',
    padding: '0 4px',
    fontSize: 11,
    lineHeight: '18px',
    borderRadius: 3,
    border: `1px solid ${token.colorBorderSecondary}`,
    background: token.colorBgContainer,
  };
}

const GROUP_HEADER_STYLE: React.CSSProperties = {
  padding: '8px 16px 4px',
  fontSize: 11,
  fontWeight: 600,
  textTransform: 'uppercase',
  letterSpacing: '0.05em',
};

/** Render a group of command items with a header */
function CommandGroupSection({
  groupKey,
  items,
  flatIndexRef,
  selectedIndex,
  favoritePaths,
  token,
  onSelect,
  onHover,
}: {
  groupKey: string;
  items: CommandItem[];
  flatIndexRef: { current: number };
  selectedIndex: number;
  favoritePaths: Set<string>;
  token: GlobalToken;
  onSelect: (item: FlatItem) => void;
  onHover: (idx: number) => void;
}) {
  const label =
    groupKey === 'recent'
      ? 'Recent'
      : groupKey === 'favorites'
        ? 'Favorites'
        : CATEGORY_LABELS[groupKey as CommandCategory] ?? groupKey;

  return (
    <div>
      <div style={{ ...GROUP_HEADER_STYLE, color: token.colorTextSecondary }}>
        {label}
        <Text
          type="secondary"
          style={{ float: 'right', fontSize: 11, fontWeight: 400, textTransform: 'none', letterSpacing: 0 }}
        >
          {items.length} {items.length === 1 ? 'result' : 'results'}
        </Text>
      </div>
      {items.map((item) => {
        const idx = flatIndexRef.current++;
        const isFav = favoritePaths.has(item.path);
        return (
          <ResultRow
            key={item.id}
            index={idx}
            selected={idx === selectedIndex}
            icon={ICON_MAP[item.icon ?? ''] ?? <SearchOutlined />}
            title={item.title}
            description={item.description}
            badge={
              <>
                {isFav && <StarFilled style={{ fontSize: 10, color: '#faad14' }} />}
                {item.category === 'action' && (
                  <ThunderboltOutlined style={{ fontSize: 10, color: token.colorWarning }} />
                )}
              </>
            }
            subtitle={item.group}
            token={token}
            onSelect={() => onSelect({ type: 'command', item })}
            onHover={() => onHover(idx)}
          />
        );
      })}
    </div>
  );
}

/** Render a group of entity results with a header */
function EntityGroupSection({
  entityType,
  items,
  flatIndexRef,
  selectedIndex,
  token,
  onSelect,
  onHover,
}: {
  entityType: string;
  items: EntityResult[];
  flatIndexRef: { current: number };
  selectedIndex: number;
  token: GlobalToken;
  onSelect: (item: FlatItem) => void;
  onHover: (idx: number) => void;
}) {
  return (
    <div>
      <div style={{ ...GROUP_HEADER_STYLE, color: token.colorTextSecondary }}>
        {entityType}s
        <Text
          type="secondary"
          style={{ float: 'right', fontSize: 11, fontWeight: 400, textTransform: 'none', letterSpacing: 0 }}
        >
          {items.length} {items.length === 1 ? 'result' : 'results'}
        </Text>
      </div>
      {items.map((item) => {
        const idx = flatIndexRef.current++;
        return (
          <ResultRow
            key={item.id}
            index={idx}
            selected={idx === selectedIndex}
            icon={ICON_MAP[item.icon ?? ''] ?? <SearchOutlined />}
            title={item.title}
            subtitle={item.subtitle || item.entityType}
            token={token}
            onSelect={() => onSelect({ type: 'entity', item })}
            onHover={() => onHover(idx)}
          />
        );
      })}
    </div>
  );
}

/** Single result row */
function ResultRow({
  index,
  selected,
  icon,
  title,
  description,
  subtitle,
  badge,
  token,
  onSelect,
  onHover,
}: {
  index: number;
  selected: boolean;
  icon: React.ReactNode;
  title: string;
  description?: string;
  subtitle?: string;
  badge?: React.ReactNode;
  token: GlobalToken;
  onSelect: () => void;
  onHover: () => void;
}) {
  return (
    <div
      data-index={index}
      onClick={onSelect}
      onMouseEnter={onHover}
      style={{
        padding: '8px 16px',
        display: 'flex',
        alignItems: 'center',
        gap: 10,
        cursor: 'pointer',
        background: selected ? token.colorPrimaryBg : 'transparent',
        borderRadius: 4,
        margin: '0 4px',
        transition: 'background 0.1s',
      }}
    >
      <span style={{ fontSize: 16, color: token.colorTextSecondary, flexShrink: 0, width: 20, textAlign: 'center' }}>
        {icon}
      </span>
      <span style={{ flex: 1, overflow: 'hidden', minWidth: 0 }}>
        <span
          style={{
            display: 'block',
            overflow: 'hidden',
            textOverflow: 'ellipsis',
            whiteSpace: 'nowrap',
            color: token.colorText,
            fontSize: 14,
          }}
        >
          {title}
        </span>
        {description && (
          <span
            style={{
              display: 'block',
              overflow: 'hidden',
              textOverflow: 'ellipsis',
              whiteSpace: 'nowrap',
              color: token.colorTextTertiary,
              fontSize: 12,
              lineHeight: '16px',
            }}
          >
            {description}
          </span>
        )}
      </span>
      {badge}
      {subtitle && (
        <Text type="secondary" style={{ fontSize: 12, flexShrink: 0 }}>
          {subtitle}
        </Text>
      )}
    </div>
  );
}
