import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';
import { useAppStore, PostData, MediaData } from '../../store';
import { showToast } from '../Toast';
import { BDS_EVENT_SCRIPTS_CHANGED, BDS_EVENT_TEMPLATES_CHANGED, dispatchWindowEvent, getContrastColor, groupPostsByStatus, loadTagColorMap } from '../../utils';
import type { ChatConversation, ImportDefinitionData } from '../../types/electron';
import { GitSidebar } from '../GitSidebar/GitSidebar';
import { scrollToSettingsSection, SettingsCategory } from '../SettingsView/SettingsView';
import { scrollToTagsSection, TagsCategory } from '../TagsView';
import { activateSidebarSection } from '../../navigation/sectionActivation';
import { getPersistedSidebarSection, setPersistedSidebarSection } from '../../navigation/sidebarUiPersistence';
import { openChatTab, openEntityTab, openImportTab, openScriptTab, openTemplateTab, openSingletonToolTab } from '../../navigation/tabPolicy';
import { createAndFocusPost } from '../../navigation/postCreation';
import type { SidebarView } from '../../navigation/sidebarViewRegistry';
import { useI18n } from '../../i18n';
import { useProjectScopedSidebarData } from './useProjectScopedSidebarData';
import { SidebarEntityList } from './SidebarEntityList';
import { formatSidebarRelativeDate } from './sidebarDateFormatting';
import './Sidebar.css';

/** Get display name for media: title (truncated to 60 chars) or fallback to filename */
function getMediaDisplayName(media: MediaData): string {
  if (media.title) {
    return media.title.length > 60 
      ? media.title.substring(0, 60) + '...' 
      : media.title;
  }
  return media.originalName;
}

const UI_DATE_LOCALE: Record<string, string> = {
  en: 'en-US',
  de: 'de-DE',
  fr: 'fr-FR',
  it: 'it-IT',
  es: 'es-ES',
};

const formatDate = (dateString: string, locale: string = 'en-US') => {
  const date = new Date(dateString);
  return date.toLocaleDateString(locale, { month: 'short', day: 'numeric', year: 'numeric' });
};

const formatFileSize = (bytes: number) => {
  if (bytes < 1024) return bytes + ' B';
  if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
  return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
};

// Get post type icon based on categories
const getPostTypeIcon = (categories: string[]): { icon: string; type: string } => {
  const lowerCategories = categories.map(c => c.toLowerCase());
  if (lowerCategories.includes('picture') || lowerCategories.includes('photo') || lowerCategories.includes('image')) {
    return { icon: '🖼️', type: 'picture' };
  }
  if (lowerCategories.includes('aside') || lowerCategories.includes('note') || lowerCategories.includes('quick')) {
    return { icon: '📝', type: 'aside' };
  }
  if (lowerCategories.includes('link') || lowerCategories.includes('bookmark')) {
    return { icon: '🔗', type: 'link' };
  }
  if (lowerCategories.includes('video')) {
    return { icon: '🎬', type: 'video' };
  }
  if (lowerCategories.includes('quote')) {
    return { icon: '💬', type: 'quote' };
  }
  // Default to article
  return { icon: '📄', type: 'article' };
};

const MONTH_NAMES = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];

const PAGE_CATEGORY = 'page';

const hasPageCategory = (post: PostData): boolean =>
  post.categories.some((category) => category.toLowerCase() === PAGE_CATEGORY);

const applyPageFilter = (posts: PostData[], isPagesMode: boolean): PostData[] =>
  isPagesMode ? posts.filter(hasPageCategory) : posts;

const mergeWithPageCategory = (categories: string[], isPagesMode: boolean): string[] => {
  if (!isPagesMode) {
    return categories;
  }

  const normalized = new Set(categories.map((category) => category.toLowerCase()));
  if (normalized.has(PAGE_CATEGORY)) {
    return categories;
  }

  return [...categories, PAGE_CATEGORY];
};

interface CalendarViewProps {
  onDateSelect: (year: number, month?: number) => void;
  selectedYear?: number;
  selectedMonth?: number;
}

const CalendarView: React.FC<CalendarViewProps> = ({ onDateSelect, selectedYear, selectedMonth }) => {
  const { t } = useI18n();
  const [yearMonthData, setYearMonthData] = useState<{ year: number; month: number; count: number }[]>([]);
  const [expandedYear, setExpandedYear] = useState<number | null>(null);
  const [isCollapsed, setIsCollapsed] = useState(true);

  useEffect(() => {
    const loadData = async () => {
      const data = await window.electronAPI?.posts.getByYearMonth();
      if (data) {
        setYearMonthData(data as { year: number; month: number; count: number }[]);
      }
    };
    loadData();
  }, []);

  // Group by year
  const years = [...new Set(yearMonthData.map(d => d.year))].sort((a, b) => b - a);

  const getYearCount = (year: number) => {
    return yearMonthData.filter(d => d.year === year).reduce((sum, d) => sum + d.count, 0);
  };

  const getMonthsForYear = (year: number) => {
    return yearMonthData.filter(d => d.year === year).sort((a, b) => b.month - a.month);
  };

  return (
    <div className="calendar-view">
      <div 
        className={`calendar-header collapsible-header ${isCollapsed ? 'collapsed' : 'expanded'}`}
        onClick={() => setIsCollapsed(!isCollapsed)}
      >
        <span className="collapse-icon">{isCollapsed ? '▶' : '▼'}</span>
        <span>{t('sidebar.archive')}</span>
        {(selectedYear || selectedMonth !== undefined) && (
          <button 
            className="clear-filter" 
            onClick={(e) => { e.stopPropagation(); onDateSelect(0); }} 
            title={t('sidebar.clearFilter')}
          >
            ✕
          </button>
        )}
      </div>
      {!isCollapsed && <div className="calendar-years">
        {years.map(year => (
          <div key={year} className="calendar-year">
            <div 
              className={`calendar-year-header ${selectedYear === year && selectedMonth === undefined ? 'selected' : ''}`}
              onClick={() => {
                setExpandedYear(expandedYear === year ? null : year);
                onDateSelect(year);
              }}
            >
              <span className="expand-icon">{expandedYear === year ? '▼' : '▶'}</span>
              <span className="year-label">{year}</span>
              <span className="year-count">{getYearCount(year)}</span>
            </div>
            {expandedYear === year && (
              <div className="calendar-months">
                {getMonthsForYear(year).map(({ month, count }) => (
                  <div
                    key={month}
                    className={`calendar-month ${selectedYear === year && selectedMonth === month ? 'selected' : ''}`}
                    onClick={(e) => {
                      e.stopPropagation();
                      onDateSelect(year, month);
                    }}
                  >
                    <span className="month-label">{MONTH_NAMES[month - 1]}</span>
                    <span className="month-count">{count}</span>
                  </div>
                ))}
              </div>
            )}
          </div>
        ))}
        {years.length === 0 && (
          <div className="calendar-empty">{t('sidebar.noPostsYet')}</div>
        )}
      </div>}
    </div>
  );
};

interface FilterPanelProps {
  tags: string[];
  tagColors: Map<string, string>;
  categories: string[];
  selectedTags: string[];
  selectedCategories: string[];
  onTagSelect: (tags: string[]) => void;
  onCategorySelect: (categories: string[]) => void;
}

const FilterPanel: React.FC<FilterPanelProps> = ({
  tags,
  tagColors,
  categories,
  selectedTags,
  selectedCategories,
  onTagSelect,
  onCategorySelect,
}) => {
  const { t } = useI18n();
  const [tagsCollapsed, setTagsCollapsed] = useState(true);
  const [categoriesCollapsed, setCategoriesCollapsed] = useState(true);

  return (
    <div className="filter-panel">
      {tags.length > 0 && (
        <div className="filter-section">
          <div 
            className={`filter-header collapsible-header ${tagsCollapsed ? 'collapsed' : 'expanded'}`}
            onClick={() => setTagsCollapsed(!tagsCollapsed)}
          >
            <span className="collapse-icon">{tagsCollapsed ? '▶' : '▼'}</span>
            <span>{t('sidebar.tags')}</span>
            {selectedTags.length > 0 && (
              <button 
                className="clear-filter" 
                onClick={(e) => { e.stopPropagation(); onTagSelect([]); }} 
                title={t('sidebar.clearTags')}
              >
                ✕
              </button>
            )}
          </div>
          {!tagsCollapsed && <div className="filter-chips">
            {tags.map(tag => {
              const color = tagColors.get(tag);
              const hasColor = !!color;
              const style: React.CSSProperties = hasColor
                ? {
                    backgroundColor: color,
                    color: getContrastColor(color!),
                    borderColor: color,
                  }
                : {};
              return (
                <button
                  key={tag}
                  className={`filter-chip ${selectedTags.includes(tag) ? 'active' : ''} ${hasColor ? 'has-color' : ''}`}
                  style={style}
                  onClick={() => {
                    if (selectedTags.includes(tag)) {
                      onTagSelect(selectedTags.filter(t => t !== tag));
                    } else {
                      onTagSelect([...selectedTags, tag]);
                    }
                  }}
                >
                  {tag}
                </button>
              );
            })}
          </div>}
        </div>
      )}
      {categories.length > 0 && (
        <div className="filter-section">
          <div 
            className={`filter-header collapsible-header ${categoriesCollapsed ? 'collapsed' : 'expanded'}`}
            onClick={() => setCategoriesCollapsed(!categoriesCollapsed)}
          >
            <span className="collapse-icon">{categoriesCollapsed ? '▶' : '▼'}</span>
            <span>{t('sidebar.categories')}</span>
            {selectedCategories.length > 0 && (
              <button 
                className="clear-filter" 
                onClick={(e) => { e.stopPropagation(); onCategorySelect([]); }} 
                title={t('sidebar.clearCategories')}
              >
                ✕
              </button>
            )}
          </div>
          {!categoriesCollapsed && <div className="filter-chips">
            {categories.map(cat => (
              <button
                key={cat}
                className={`filter-chip ${selectedCategories.includes(cat) ? 'active' : ''}`}
                onClick={() => {
                  if (selectedCategories.includes(cat)) {
                    onCategorySelect(selectedCategories.filter(c => c !== cat));
                  } else {
                    onCategorySelect([...selectedCategories, cat]);
                  }
                }}
              >
                {cat}
              </button>
            ))}
          </div>}
        </div>
      )}
    </div>
  );
};

// Media-specific calendar view
interface MediaCalendarViewProps {
  onDateSelect: (year: number, month?: number) => void;
  selectedYear?: number;
  selectedMonth?: number;
}

const MediaCalendarView: React.FC<MediaCalendarViewProps> = ({ onDateSelect, selectedYear, selectedMonth }) => {
  const { t } = useI18n();
  const [yearMonthData, setYearMonthData] = useState<{ year: number; month: number; count: number }[]>([]);
  const [expandedYear, setExpandedYear] = useState<number | null>(null);
  const [isCollapsed, setIsCollapsed] = useState(true);

  useEffect(() => {
    const loadData = async () => {
      const data = await window.electronAPI?.media.getByYearMonth();
      if (data) {
        setYearMonthData(data as { year: number; month: number; count: number }[]);
      }
    };
    loadData();
  }, []);

  const years = [...new Set(yearMonthData.map(d => d.year))].sort((a, b) => b - a);

  const getYearCount = (year: number) => {
    return yearMonthData.filter(d => d.year === year).reduce((sum, d) => sum + d.count, 0);
  };

  const getMonthsForYear = (year: number) => {
    return yearMonthData.filter(d => d.year === year).sort((a, b) => b.month - a.month);
  };

  return (
    <div className="calendar-view">
      <div 
        className={`calendar-header collapsible-header ${isCollapsed ? 'collapsed' : 'expanded'}`}
        onClick={() => setIsCollapsed(!isCollapsed)}
      >
        <span className="collapse-icon">{isCollapsed ? '▶' : '▼'}</span>
        <span>{t('sidebar.archive')}</span>
        {(selectedYear || selectedMonth !== undefined) && (
          <button 
            className="clear-filter" 
            onClick={(e) => { e.stopPropagation(); onDateSelect(0); }} 
            title={t('sidebar.clearFilter')}
          >
            ✕
          </button>
        )}
      </div>
      {!isCollapsed && <div className="calendar-years">
        {years.map(year => (
          <div key={year} className="calendar-year">
            <div
              className={`calendar-year-header ${selectedYear === year && selectedMonth === undefined ? 'selected' : ''}`}
              onClick={() => {
                setExpandedYear(expandedYear === year ? null : year);
                onDateSelect(year);
              }}
            >
              <span className="expand-icon">{expandedYear === year ? '▼' : '▶'}</span>
              <span className="year-label">{year}</span>
              <span className="year-count">{getYearCount(year)}</span>
            </div>
            {expandedYear === year && (
              <div className="calendar-months">
                {getMonthsForYear(year).map(({ month, count }) => (
                  <div
                    key={month}
                    className={`calendar-month ${selectedYear === year && selectedMonth === month ? 'selected' : ''}`}
                    onClick={(e) => {
                      e.stopPropagation();
                      onDateSelect(year, month);
                    }}
                  >
                    <span className="month-label">{MONTH_NAMES[month - 1]}</span>
                    <span className="month-count">{count}</span>
                  </div>
                ))}
              </div>
            )}
          </div>
        ))}
        {years.length === 0 && (
          <div className="calendar-empty">{t('sidebar.noMediaYet')}</div>
        )}
      </div>}
    </div>
  );
};

// Media-specific filter panel
interface MediaFilterPanelProps {
  tags: string[];
  tagColors: Map<string, string>;
  selectedTags: string[];
  onTagSelect: (tags: string[]) => void;
}

const MediaFilterPanel: React.FC<MediaFilterPanelProps> = ({
  tags,
  tagColors,
  selectedTags,
  onTagSelect,
}) => {
  const { t } = useI18n();
  const [tagsCollapsed, setTagsCollapsed] = useState(true);

  return (
    <div className="filter-panel">
      {tags.length > 0 && (
        <div className="filter-section">
          <div 
            className={`filter-header collapsible-header ${tagsCollapsed ? 'collapsed' : 'expanded'}`}
            onClick={() => setTagsCollapsed(!tagsCollapsed)}
          >
            <span className="collapse-icon">{tagsCollapsed ? '▶' : '▼'}</span>
            <span>{t('sidebar.tags')}</span>
            {selectedTags.length > 0 && (
              <button 
                className="clear-filter" 
                onClick={(e) => { e.stopPropagation(); onTagSelect([]); }} 
                title={t('sidebar.clearTags')}
              >
                ✕
              </button>
            )}
          </div>
          {!tagsCollapsed && <div className="filter-chips">
            {tags.map(tag => {
              const color = tagColors.get(tag);
              const hasColor = !!color;
              const style: React.CSSProperties = hasColor
                ? {
                    backgroundColor: color,
                    color: getContrastColor(color!),
                    borderColor: color,
                  }
                : {};
              return (
                <button
                  key={tag}
                  className={`filter-chip ${selectedTags.includes(tag) ? 'active' : ''} ${hasColor ? 'has-color' : ''}`}
                  style={style}
                  onClick={() => {
                    if (selectedTags.includes(tag)) {
                      onTagSelect(selectedTags.filter(t => t !== tag));
                    } else {
                      onTagSelect([...selectedTags, tag]);
                    }
                  }}
                >
                  {tag}
                </button>
              );
            })}
          </div>}
        </div>
      )}
    </div>
  );
};

interface SearchBoxProps {
  onSearch: (query: string) => void;
  placeholder: string;
}

const SearchBox: React.FC<SearchBoxProps> = ({ onSearch, placeholder }) => {
  const { t } = useI18n();
  const [query, setQuery] = useState('');

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    onSearch(query);
  };

  return (
    <form className="search-box" onSubmit={handleSubmit}>
      <input
        type="text"
        placeholder={placeholder}
        value={query}
        onChange={(e) => setQuery(e.target.value)}
      />
      <button type="submit" title={t('sidebar.search')}>
        <svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor">
          <path d="M15.7 14.3l-4.2-4.2c-.2-.2-.5-.3-.8-.3.9-1.1 1.5-2.5 1.5-4C12.2 2.6 9.6 0 6.4 0S.6 2.6.6 5.8s2.6 5.8 5.8 5.8c1.5 0 2.9-.5 4-1.4 0 .3.1.6.3.8l4.2 4.2c.2.2.5.3.7.3s.5-.1.7-.3c.4-.4.4-1 0-1.4zm-9.3-4c-2.5 0-4.5-2-4.5-4.5s2-4.5 4.5-4.5 4.5 2 4.5 4.5-2 4.5-4.5 4.5z"/>
        </svg>
      </button>
      {query && (
        <button type="button" className="clear-search" onClick={() => { setQuery(''); onSearch(''); }} title={t('common.clear')}>
          ✕
        </button>
      )}
    </form>
  );
};

type PostsListMode = 'posts' | 'pages';

interface PostsListProps {
  mode: PostsListMode;
  isActive: boolean;
}

const PostsList: React.FC<PostsListProps> = ({ mode, isActive }) => {
  const { t, language } = useI18n();
  const uiLocale = UI_DATE_LOCALE[language] || UI_DATE_LOCALE.en;
  const { posts, hasMorePosts, totalPosts, appendPosts, openTab, activeTabId } = useAppStore();
  const isPagesMode = mode === 'pages';
  const postSubset = useMemo(() => applyPageFilter(posts, isPagesMode), [posts, isPagesMode]);
  const [pageBasePosts, setPageBasePosts] = useState<PostData[] | null>(null);
  
  // Filter state
  const [searchQuery, setSearchQuery] = useState('');
  const [searchResults, setSearchResults] = useState<PostData[] | null>(null);
  const [selectedYear, setSelectedYear] = useState<number | undefined>();
  const [selectedMonth, setSelectedMonth] = useState<number | undefined>();
  const [selectedTags, setSelectedTags] = useState<string[]>([]);
  const [selectedCategories, setSelectedCategories] = useState<string[]>([]);
  const [availableTags, setAvailableTags] = useState<string[]>([]);
  const [tagColors, setTagColors] = useState<Map<string, string>>(new Map());
  const [availableCategories, setAvailableCategories] = useState<string[]>([]);
  const [showFilters, setShowFilters] = useState(false);
  const [filteredPosts, setFilteredPosts] = useState<PostData[] | null>(null);
  const [isLoadingMore, setIsLoadingMore] = useState(false);

  // Load available tags with colors and categories
  useEffect(() => {
    const loadFilters = async () => {
      const [tags, categories, colorMap] = await Promise.all([
        window.electronAPI?.posts.getTags(),
        window.electronAPI?.posts.getCategories(),
        loadTagColorMap(),
      ]);
      if (tags) setAvailableTags(tags as string[]);
      if (categories) {
        const allCategories = categories as string[];
        setAvailableCategories(
          isPagesMode
            ? allCategories.filter((category) => category.toLowerCase() !== PAGE_CATEGORY)
            : allCategories
        );
      }
      setTagColors(colorMap);
    };
    loadFilters();
  }, [posts]);

  // In pages mode, load the full pages subset from backend filtering,
  // independent of currently paged post list in the store.
  useEffect(() => {
    if (!isPagesMode || !isActive) {
      return;
    }

    let isCancelled = false;

    const loadPagesBase = async () => {
      try {
        const results = await window.electronAPI?.posts.filter({ categories: [PAGE_CATEGORY] });
        if (!isCancelled && results) {
          setPageBasePosts(results as PostData[]);
        }
      } catch (error) {
        if (!isCancelled) {
          console.error('Failed to load pages subset:', error);
        }
      }
    };

    loadPagesBase();

    return () => {
      isCancelled = true;
    };
  }, [isPagesMode, isActive, posts]);

  // Handle search
  const handleSearch = async (query: string) => {
    setSearchQuery(query);
    if (!query.trim()) {
      setSearchResults(null);
      return;
    }
    try {
      const results = await window.electronAPI?.posts.search(query);
      if (results) {
        // Fetch full PostData for each search result
        const fullPosts: PostData[] = [];
        for (const result of results as { id: string }[]) {
          const post = await window.electronAPI?.posts.get(result.id);
          if (post) {
            fullPosts.push(post as PostData);
          }
        }
        setSearchResults(applyPageFilter(fullPosts, isPagesMode));
      }
    } catch (error) {
      console.error('Search failed:', error);
      showToast.error(t('sidebar.search'));
    }
  };

  // Handle date selection
  const handleDateSelect = async (year: number, month?: number) => {
    if (year === 0) {
      // Clear filter
      setSelectedYear(undefined);
      setSelectedMonth(undefined);
      setFilteredPosts(null);
      return;
    }
    setSelectedYear(year);
    setSelectedMonth(month);

    const mergedCategories = mergeWithPageCategory(selectedCategories, isPagesMode);
    
    try {
      const results = await window.electronAPI?.posts.filter({
        year,
        month,
        tags: selectedTags.length > 0 ? selectedTags : undefined,
        categories: mergedCategories.length > 0 ? mergedCategories : undefined,
      });
      if (results) {
        setFilteredPosts(applyPageFilter(results as PostData[], isPagesMode));
      }
    } catch (error) {
      console.error('Filter failed:', error);
    }
  };

  // Handle tag/category filter changes
  useEffect(() => {
    const applyFilters = async () => {
      if (!selectedYear && selectedTags.length === 0 && selectedCategories.length === 0) {
        setFilteredPosts(null);
        return;
      }

      const mergedCategories = mergeWithPageCategory(selectedCategories, isPagesMode);
      
      try {
        const results = await window.electronAPI?.posts.filter({
          year: selectedYear,
          month: selectedMonth,
          tags: selectedTags.length > 0 ? selectedTags : undefined,
          categories: mergedCategories.length > 0 ? mergedCategories : undefined,
        });
        if (results) {
          setFilteredPosts(applyPageFilter(results as PostData[], isPagesMode));
        }
      } catch (error) {
        console.error('Filter failed:', error);
      }
    };
    applyFilters();
  }, [selectedTags, selectedCategories, selectedYear, selectedMonth, isPagesMode]);

  // Track previous post statuses to detect changes
  const prevPostStatusMapRef = useRef<Map<string, string>>(new Map());
  
  // Re-run search/filter when a post's status changes (e.g., draft becomes published or vice versa)
  // This ensures the sidebar lists are always up-to-date without stale cached data
  useEffect(() => {
    const currentStatusMap = new Map(posts.map(p => [p.id, p.status]));
    const prevStatusMap = prevPostStatusMapRef.current;
    
    // Check if any post's status changed
    let statusChanged = false;
    for (const [id, status] of currentStatusMap) {
      const prevStatus = prevStatusMap.get(id);
      if (prevStatus !== undefined && prevStatus !== status) {
        statusChanged = true;
        break;
      }
    }
    
    // Update the ref for next comparison
    prevPostStatusMapRef.current = currentStatusMap;
    
    // If a status changed and we have active filters, re-run them to get fresh data
    if (statusChanged) {
      if (searchQuery) {
        // Re-run search inline to avoid dependency on handleSearch
        const refreshSearch = async () => {
          try {
            const results = await window.electronAPI?.posts.search(searchQuery);
            if (results) {
              const fullPosts: PostData[] = [];
              for (const result of results as { id: string }[]) {
                const post = await window.electronAPI?.posts.get(result.id);
                if (post) {
                  fullPosts.push(post as PostData);
                }
              }
              setSearchResults(applyPageFilter(fullPosts, isPagesMode));
            }
          } catch (error) {
            console.error('Search refresh failed:', error);
          }
        };
        refreshSearch();
      } else if (selectedYear || selectedTags.length > 0 || selectedCategories.length > 0) {
        // Re-run filter
        const refetchFilters = async () => {
          const mergedCategories = mergeWithPageCategory(selectedCategories, isPagesMode);
          try {
            const results = await window.electronAPI?.posts.filter({
              year: selectedYear,
              month: selectedMonth,
              tags: selectedTags.length > 0 ? selectedTags : undefined,
              categories: mergedCategories.length > 0 ? mergedCategories : undefined,
            });
            if (results) {
              setFilteredPosts(applyPageFilter(results as PostData[], isPagesMode));
            }
          } catch (error) {
            console.error('Filter refresh failed:', error);
          }
        };
        refetchFilters();
      } else {
        // No active filters, just clear any stale cached results
        setSearchResults(null);
        setFilteredPosts(null);
      }
    }
  }, [posts, searchQuery, selectedYear, selectedMonth, selectedTags, selectedCategories, isPagesMode]);

  const handleCreatePost = async () => {
    const { setSelectedPost: selectPost } = useAppStore.getState();
    await createAndFocusPost({
      createPost: async (input) => (await window.electronAPI?.posts.create(input)) as { id: string } | null | undefined,
      setSelectedPost: selectPost,
      onError: (error) => {
        console.error('Failed to create post:', error);
      },
    });
  };

  const handleLoadMore = async () => {
    if (isLoadingMore || !hasMorePosts) return;
    
    setIsLoadingMore(true);
    try {
      const postsResult = await window.electronAPI?.posts.getAll({ limit: 500, offset: posts.length });
      if (postsResult) {
        const { items, hasMore } = postsResult as { items: PostData[]; hasMore: boolean };
        appendPosts(items, hasMore);
      }
    } catch (error) {
      console.error('Failed to load more posts:', error);
      showToast.error('Failed to load more posts');
    } finally {
      setIsLoadingMore(false);
    }
  };

  // Determine which posts to display
  // Filters only apply to published/archived posts — drafts are always shown unfiltered
  const filteredDisplayPosts = searchResults ?? filteredPosts ?? (isPagesMode ? pageBasePosts : null);
  const isFiltered = filteredDisplayPosts !== null;
  const hasActiveFilters = searchQuery || selectedYear || selectedTags.length > 0 || selectedCategories.length > 0;

  const baseDisplayPosts = isPagesMode ? (pageBasePosts ?? postSubset) : postSubset;

  // Memoized grouping that freshens cached filter results with current store data
  // This ensures status changes are reflected even when filters are active
  const groupedPosts = useMemo(
    () => groupPostsByStatus(baseDisplayPosts, filteredDisplayPosts),
    [baseDisplayPosts, filteredDisplayPosts]
  );

  const clearAllFilters = () => {
    setSearchQuery('');
    setSearchResults(null);
    setSelectedYear(undefined);
    setSelectedMonth(undefined);
    setSelectedTags([]);
    setSelectedCategories([]);
    setFilteredPosts(null);
  };

  // Click handlers for tabs
  const handlePostClick = (postId: string) => {
    openEntityTab(openTab, 'post', postId, 'preview');
  };

  const handlePostDoubleClick = (postId: string) => {
    openEntityTab(openTab, 'post', postId, 'pin');
  };

  return (
    <div className="sidebar-content">
      <div className="sidebar-section">
        <div className="sidebar-section-header">
          <span>{(isPagesMode ? t('activity.pages') : t('activity.posts')).toUpperCase()}</span>
          <div className="sidebar-actions">
            <button 
              className={`sidebar-action ${showFilters ? 'active' : ''}`} 
              onClick={() => setShowFilters(!showFilters)} 
              title={t('sidebar.toggleFilters')}
            >
              <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
                <path d="M6 12v-1h4v1H6zM4 8v-1h8v1H4zm-2-4v-1h12v1H2z"/>
              </svg>
            </button>
            <button className="sidebar-action" onClick={handleCreatePost} title={t('sidebar.newPost')}>
              <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
                <path d="M14 7v1H8v6H7V8H1V7h6V1h1v6h6z"/>
              </svg>
            </button>
          </div>
        </div>
      </div>

      <SearchBox
        onSearch={handleSearch}
        placeholder={isPagesMode ? t('sidebar.searchPagesPlaceholder') : t('sidebar.searchPostsPlaceholder')}
      />
      
      {showFilters && (
        <>
          <CalendarView 
            onDateSelect={handleDateSelect}
            selectedYear={selectedYear}
            selectedMonth={selectedMonth}
          />
          <FilterPanel
            tags={availableTags}
            tagColors={tagColors}
            categories={availableCategories}
            selectedTags={selectedTags}
            selectedCategories={selectedCategories}
            onTagSelect={setSelectedTags}
            onCategorySelect={setSelectedCategories}
          />
        </>
      )}

      {hasActiveFilters && (
        <div className="filter-status">
          <span>
            {searchQuery
              ? t('sidebar.resultsFor', {
                  count: groupedPosts.published.length + groupedPosts.archived.length,
                  query: searchQuery,
                })
              : t('sidebar.results', { count: groupedPosts.published.length + groupedPosts.archived.length })}
          </span>
          <button onClick={clearAllFilters} title={t('sidebar.clearFilters')}>
            {t('sidebar.clearFilters')}
          </button>
        </div>
      )}

      {groupedPosts.draft.length > 0 && (
        <div className="sidebar-section">
          <div className="sidebar-section-title">
            <span className="section-icon status-draft">●</span>
            {t('sidebar.drafts')} ({groupedPosts.draft.length})
          </div>
          <div className="sidebar-list">
            {groupedPosts.draft.map(post => {
              const postType = getPostTypeIcon(post.categories);
              return (
                <div
                  key={post.id}
                  className={`sidebar-item post-type-${postType.type} ${activeTabId === post.id ? 'selected' : ''}`}
                  onClick={() => handlePostClick(post.id)}
                  onDoubleClick={() => handlePostDoubleClick(post.id)}
                >
                  <span className="post-type-icon" title={postType.type}>{postType.icon}</span>
                  <div className="sidebar-item-content">
                    <div className="sidebar-item-title">{post.title || t('sidebar.untitled')}</div>
                    <div className="sidebar-item-meta">{formatDate(post.updatedAt, uiLocale)}</div>
                  </div>
                </div>
              );
            })}
          </div>
        </div>
      )}

      {groupedPosts.published.length > 0 && (
        <div className="sidebar-section">
          <div className="sidebar-section-title">
            <span className="section-icon status-published">●</span>
            {t('sidebar.published')} ({groupedPosts.published.length})
          </div>
          <div className="sidebar-list">
            {groupedPosts.published.map(post => {
              const postType = getPostTypeIcon(post.categories);
              return (
                <div
                  key={post.id}
                  className={`sidebar-item post-type-${postType.type} ${activeTabId === post.id ? 'selected' : ''}`}
                  onClick={() => handlePostClick(post.id)}
                  onDoubleClick={() => handlePostDoubleClick(post.id)}
                >
                  <span className="post-type-icon" title={postType.type}>{postType.icon}</span>
                  <div className="sidebar-item-content">
                    <div className="sidebar-item-title">{post.title || t('sidebar.untitled')}</div>
                    <div className="sidebar-item-meta">{formatDate(post.publishedAt || post.updatedAt, uiLocale)}</div>
                  </div>
                </div>
              );
            })}
          </div>
        </div>
      )}

      {groupedPosts.archived.length > 0 && (
        <div className="sidebar-section">
          <div className="sidebar-section-title">
            <span className="section-icon status-archived">●</span>
            {t('sidebar.archived')} ({groupedPosts.archived.length})
          </div>
          <div className="sidebar-list">
            {groupedPosts.archived.map(post => {
              const postType = getPostTypeIcon(post.categories);
              return (
                <div
                  key={post.id}
                  className={`sidebar-item post-type-${postType.type} ${activeTabId === post.id ? 'selected' : ''}`}
                  onClick={() => handlePostClick(post.id)}
                  onDoubleClick={() => handlePostDoubleClick(post.id)}
                >
                  <span className="post-type-icon" title={postType.type}>{postType.icon}</span>
                  <div className="sidebar-item-content">
                    <div className="sidebar-item-title">{post.title || t('sidebar.untitled')}</div>
                    <div className="sidebar-item-meta">{formatDate(post.updatedAt, uiLocale)}</div>
                  </div>
                </div>
              );
            })}
          </div>
        </div>
      )}

      {baseDisplayPosts.length === 0 && !isFiltered && (
        <div className="sidebar-empty">
          <p>{isPagesMode ? t('sidebar.noPagesYet') : t('sidebar.noPostsYet')}</p>
          <button onClick={handleCreatePost}>{t('sidebar.createFirstPost')}</button>
        </div>
      )}

      {groupedPosts.published.length === 0 && groupedPosts.archived.length === 0 && isFiltered && (
        <div className="sidebar-empty">
          <p>{t('sidebar.noMatchingPosts')}</p>
          <button onClick={clearAllFilters}>{t('sidebar.clearFilters')}</button>
        </div>
      )}

      {/* Load More button - only show when not filtering and has more posts */}
      {!isFiltered && hasMorePosts && (
        <div className="sidebar-load-more">
          <button 
            onClick={handleLoadMore} 
            disabled={isLoadingMore}
            className="load-more-button"
          >
            {isLoadingMore ? t('sidebar.loading') : t('sidebar.loadMore', { loaded: posts.length, total: totalPosts })}
          </button>
        </div>
      )}
    </div>
  );
};

const MediaList: React.FC = () => {
  const { t } = useI18n();
  const { media, openTab, activeTabId } = useAppStore();

  // Filter state
  const [searchQuery, setSearchQuery] = useState('');
  const [searchResults, setSearchResults] = useState<MediaData[] | null>(null);
  const [selectedYear, setSelectedYear] = useState<number | undefined>();
  const [selectedMonth, setSelectedMonth] = useState<number | undefined>();
  const [selectedTags, setSelectedTags] = useState<string[]>([]);
  const [availableTags, setAvailableTags] = useState<string[]>([]);
  const [tagColors, setTagColors] = useState<Map<string, string>>(new Map());
  const [showFilters, setShowFilters] = useState(false);
  const [filteredMedia, setFilteredMedia] = useState<MediaData[] | null>(null);

  // Load available tags with colors
  useEffect(() => {
    const loadTags = async () => {
      const [tags, colorMap] = await Promise.all([
        window.electronAPI?.media.getTags(),
        loadTagColorMap(),
      ]);
      if (tags) setAvailableTags(tags as string[]);
      setTagColors(colorMap);
    };
    loadTags();
  }, [media]);

  // Handle search
  const handleSearch = async (query: string) => {
    setSearchQuery(query);
    if (!query.trim()) {
      setSearchResults(null);
      return;
    }
    try {
      const results = await window.electronAPI?.media.search(query);
      if (results) {
        const mediaIds = (results as { id: string }[]).map(r => r.id);
        setSearchResults(media.filter(m => mediaIds.includes(m.id)));
      }
    } catch (error) {
      console.error('Search failed:', error);
      showToast.error(t('sidebar.search'));
    }
  };

  // Handle date selection
  const handleDateSelect = async (year: number, month?: number) => {
    if (year === 0) {
      // Clear filter
      setSelectedYear(undefined);
      setSelectedMonth(undefined);
      setFilteredMedia(null);
      return;
    }
    setSelectedYear(year);
    setSelectedMonth(month);

    try {
      const results = await window.electronAPI?.media.filter({
        year,
        month,
        tags: selectedTags.length > 0 ? selectedTags : undefined,
      });
      if (results) {
        setFilteredMedia(results as MediaData[]);
      }
    } catch (error) {
      console.error('Filter failed:', error);
    }
  };

  // Handle tag filter changes
  useEffect(() => {
    const applyFilters = async () => {
      if (!selectedYear && selectedTags.length === 0) {
        setFilteredMedia(null);
        return;
      }

      try {
        const results = await window.electronAPI?.media.filter({
          year: selectedYear,
          month: selectedMonth,
          tags: selectedTags.length > 0 ? selectedTags : undefined,
        });
        if (results) {
          setFilteredMedia(results as MediaData[]);
        }
      } catch (error) {
        console.error('Filter failed:', error);
      }
    };
    applyFilters();
  }, [selectedTags]);

  const handleImportMedia = async () => {
    try {
      await window.electronAPI?.media.importDialog();
    } catch (error) {
      console.error('Failed to import media:', error);
    }
  };

  const handleMediaClick = (mediaId: string) => {
    openEntityTab(openTab, 'media', mediaId, 'preview');
  };

  const handleMediaDoubleClick = (mediaId: string) => {
    openEntityTab(openTab, 'media', mediaId, 'pin');
  };

  // Determine which media to display
  const filteredDisplayMedia = searchResults ?? filteredMedia ?? media;
  const hasActiveFilters = searchQuery || selectedYear || selectedTags.length > 0;

  const clearAllFilters = () => {
    setSearchQuery('');
    setSearchResults(null);
    setSelectedYear(undefined);
    setSelectedMonth(undefined);
    setSelectedTags([]);
    setFilteredMedia(null);
  };

  return (
    <div className="sidebar-content">
      <div className="sidebar-section">
        <div className="sidebar-section-header">
          <span>{t('activity.media').toUpperCase()}</span>
          <div className="sidebar-actions">
            <button
              className={`sidebar-action ${showFilters ? 'active' : ''}`}
              onClick={() => setShowFilters(!showFilters)}
              title={t('sidebar.toggleFilters')}
            >
              <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
                <path d="M6 12v-1h4v1H6zM4 8v-1h8v1H4zm-2-4v-1h12v1H2z"/>
              </svg>
            </button>
            <button className="sidebar-action" onClick={handleImportMedia} title={t('sidebar.importMedia')}>
              <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
                <path d="M14 7v1H8v6H7V8H1V7h6V1h1v6h6z"/>
              </svg>
            </button>
          </div>
        </div>
      </div>

      <SearchBox onSearch={handleSearch} placeholder={t('sidebar.searchMediaPlaceholder')} />

      {showFilters && (
        <>
          <MediaCalendarView
            onDateSelect={handleDateSelect}
            selectedYear={selectedYear}
            selectedMonth={selectedMonth}
          />
          <MediaFilterPanel
            tags={availableTags}
            tagColors={tagColors}
            selectedTags={selectedTags}
            onTagSelect={setSelectedTags}
          />
        </>
      )}

      {hasActiveFilters && (
        <div className="filter-status">
          <span>
            {searchQuery
              ? t('sidebar.resultsFor', { count: filteredDisplayMedia.length, query: searchQuery })
              : t('sidebar.results', { count: filteredDisplayMedia.length })}
          </span>
          <button onClick={clearAllFilters} title={t('sidebar.clearFilters')}>
            {t('sidebar.clearFilters')}
          </button>
        </div>
      )}

      <div className="sidebar-list media-grid">
        {filteredDisplayMedia.map(item => (
          <div
            key={item.id}
            className={`media-item ${activeTabId === item.id ? 'selected' : ''}`}
            onClick={() => handleMediaClick(item.id)}
            onDoubleClick={() => handleMediaDoubleClick(item.id)}
            title={item.caption || item.originalName}
          >
            {item.mimeType.startsWith('image/') ? (
              <div className="media-thumbnail">
                <img
                  src={`bds-thumb://${item.id}`}
                  alt={item.alt || item.originalName}
                  onError={(e) => {
                    const target = e.target as HTMLImageElement;
                    target.style.display = 'none';
                  }}
                />
              </div>
            ) : (
              <div className="media-thumbnail">
                <svg width="32" height="32" viewBox="0 0 24 24" fill="currentColor" opacity="0.5">
                  <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z"/>
                </svg>
              </div>
            )}
            <div className="media-item-info">
              <div className="media-item-name truncate">{getMediaDisplayName(item)}</div>
              <div className="media-item-size">{formatFileSize(item.size)}</div>
            </div>
          </div>
        ))}
      </div>

      {filteredDisplayMedia.length === 0 && (
        <div className="sidebar-empty">
          <p>{t('sidebar.noMediaFiles')}</p>
          <button onClick={handleImportMedia}>{t('sidebar.importMedia')}</button>
        </div>
      )}
    </div>
  );
};

const TagsNav: React.FC = () => {
  const { t } = useI18n();
  const { tabs, activeTabId, openTab } = useAppStore();
  const [activeSection, setActiveSection] = useState<TagsCategory | null>(() => {
    const persisted = getPersistedSidebarSection('tags');
    if (persisted === 'cloud' || persisted === 'manage' || persisted === 'merge') {
      return persisted;
    }
    return null;
  });

  const isTagsTabActive = tabs.some(t => t.type === 'tags' && t.id === activeTabId);

  const handleNavClick = (category: TagsCategory) => {
    setActiveSection(category);
    setPersistedSidebarSection('tags', category);
    activateSidebarSection({
      isEditorTabActive: isTagsTabActive,
      ensureEditorTabActive: () => openSingletonToolTab(openTab, 'tags'),
      activateSection: () => scrollToTagsSection(category),
    });
  };

  return (
    <div className="sidebar-content settings-panel">
      <div className="sidebar-section">
        <div className="sidebar-section-header">
          <span>{t('sidebar.tagsHeader').toUpperCase()}</span>
        </div>
      </div>

      <div className="settings-nav-list">
        <button
          className={`settings-nav-entry ${activeSection === 'cloud' ? 'active' : ''}`}
          onClick={() => handleNavClick('cloud')}
        >
          <span className="settings-nav-entry-icon">☁️</span>
          <span>{t('sidebar.tagCloud')}</span>
        </button>
        <button
          className={`settings-nav-entry ${activeSection === 'manage' ? 'active' : ''}`}
          onClick={() => handleNavClick('manage')}
        >
          <span className="settings-nav-entry-icon">✏️</span>
          <span>{t('sidebar.createEdit')}</span>
        </button>
        <button 
          className={`settings-nav-entry ${activeSection === 'merge' ? 'active' : ''}`}
          onClick={() => handleNavClick('merge')}
        >
          <span className="settings-nav-entry-icon">🔀</span>
          <span>{t('sidebar.mergeTags')}</span>
        </button>
      </div>
    </div>
  );
};

const SettingsNav: React.FC = () => {
  const { t } = useI18n();
  const { tabs, activeTabId, openTab } = useAppStore();
  const [activeSection, setActiveSection] = useState<SettingsCategory | null>(() => {
    const persisted = getPersistedSidebarSection('settings');
    if (persisted === 'project' || persisted === 'editor' || persisted === 'content' || persisted === 'ai' || persisted === 'technology' || persisted === 'publishing' || persisted === 'data' || persisted === 'mcp') {
      return persisted;
    }
    return null;
  });

  // Check if settings panel is currently active
  const isSettingsTabActive = tabs.some(t => t.type === 'settings' && t.id === activeTabId);
  const isStyleTabActive = tabs.some(t => t.type === 'style' && t.id === activeTabId);

  const handleNavClick = (category: SettingsCategory) => {
    setActiveSection(category);
    setPersistedSidebarSection('settings', category);
    activateSidebarSection({
      isEditorTabActive: isSettingsTabActive,
      ensureEditorTabActive: () => openSingletonToolTab(openTab, 'settings'),
      activateSection: () => scrollToSettingsSection(category),
    });
  };

  const handleStyleClick = () => {
    openSingletonToolTab(openTab, 'style');
  };

  return (
    <div className="sidebar-content settings-panel">
      <div className="sidebar-section">
        <div className="sidebar-section-header">
          <span>{t('sidebar.settingsHeader').toUpperCase()}</span>
        </div>
      </div>

      <div className="settings-nav-list">
        <button
          className={`settings-nav-entry ${activeSection === 'project' ? 'active' : ''}`}
          onClick={() => handleNavClick('project')}
        >
          <span className="settings-nav-entry-icon">📁</span>
          <span>{t('sidebar.nav.project')}</span>
        </button>
        <button
          className={`settings-nav-entry ${activeSection === 'editor' ? 'active' : ''}`}
          onClick={() => handleNavClick('editor')}
        >
          <span className="settings-nav-entry-icon">📝</span>
          <span>{t('sidebar.nav.editor')}</span>
        </button>
        <button 
          className={`settings-nav-entry ${activeSection === 'content' ? 'active' : ''}`}
          onClick={() => handleNavClick('content')}
        >
          <span className="settings-nav-entry-icon">📋</span>
          <span>{t('sidebar.nav.content')}</span>
        </button>
        <button 
          className={`settings-nav-entry ${activeSection === 'ai' ? 'active' : ''}`}
          onClick={() => handleNavClick('ai')}
        >
          <span className="settings-nav-entry-icon">🤖</span>
          <span>{t('sidebar.nav.ai')}</span>
        </button>
        <button
          className={`settings-nav-entry ${activeSection === 'technology' ? 'active' : ''}`}
          onClick={() => handleNavClick('technology')}
        >
          <span className="settings-nav-entry-icon">⚙️</span>
          <span>{t('sidebar.nav.technology')}</span>
        </button>
        <button 
          className={`settings-nav-entry ${activeSection === 'publishing' ? 'active' : ''}`}
          onClick={() => handleNavClick('publishing')}
        >
          <span className="settings-nav-entry-icon">🚀</span>
          <span>{t('sidebar.nav.publishing')}</span>
        </button>
        <button 
          className={`settings-nav-entry ${activeSection === 'data' ? 'active' : ''}`}
          onClick={() => handleNavClick('data')}
        >
          <span className="settings-nav-entry-icon">🗄️</span>
          <span>{t('sidebar.nav.data')}</span>
        </button>
        <button 
          className={`settings-nav-entry ${activeSection === 'mcp' ? 'active' : ''}`}
          onClick={() => handleNavClick('mcp')}
        >
          <span className="settings-nav-entry-icon">🔌</span>
          <span>{t('sidebar.nav.mcp')}</span>
        </button>
        <button
          className={`settings-nav-entry ${isStyleTabActive ? 'active' : ''}`}
          onClick={handleStyleClick}
        >
          <span className="settings-nav-entry-icon">🎨</span>
          <span>{t('sidebar.nav.style')}</span>
        </button>
      </div>
    </div>
  );
};

// Chat conversations list
const ChatList: React.FC = () => {
  const { t, language } = useI18n();
  const { openTab, closeTab, activeProject } = useAppStore();
  const activeProjectId = activeProject?.id;
  const [isReady, setIsReady] = useState(false);

  const loadConversations = useCallback(async (): Promise<ChatConversation[]> => {
    try {
      const convs = await window.electronAPI?.chat.getConversations();
      return convs ?? [];
    } catch (error) {
      console.error('Failed to load conversations:', error);
      return [];
    }
  }, []);

  const {
    items: conversations,
    setItems: setConversations,
    isLoading,
  } = useProjectScopedSidebarData<ChatConversation>({
    load: loadConversations,
    activeProjectId,
  });

  // Check if service is ready
  const checkReady = useCallback(async () => {
    try {
      const status = await window.electronAPI?.chat.checkReady();
      setIsReady(status?.ready ?? false);
    } catch {
      setIsReady(false);
    }
  }, []);

  useEffect(() => {
    void checkReady();

    // Subscribe to title updates
    const unsubTitle = window.electronAPI?.chat.onTitleUpdated((data) => {
      setConversations(prev =>
        prev.map(c => c.id === data.conversationId ? { ...c, title: data.title } : c)
      );
    });

    return () => {
      unsubTitle?.();
    };
  }, [checkReady, setConversations]);

  const handleNewChat = async () => {
    try {
      const conversation = await window.electronAPI?.chat.createConversation();
      if (conversation) {
        setConversations(prev => [conversation, ...prev]);
        openChatTab(openTab, conversation.id);
      }
    } catch (error) {
      console.error('Failed to create conversation:', error);
      showToast.error(t('sidebar.chat.createFailed'));
    }
  };

  const handleOpenChat = (conversationId: string) => {
    openChatTab(openTab, conversationId);
  };

  const handleDeleteChat = async (conversationId: string) => {
    try {
      await window.electronAPI?.chat.deleteConversation(conversationId);
      setConversations(prev => prev.filter(c => c.id !== conversationId));
      // Close the tab for the deleted chat
      closeTab(conversationId);
    } catch (error) {
      console.error('Failed to delete conversation:', error);
      showToast.error(t('sidebar.chat.deleteFailed'));
    }
  };

  return (
    <SidebarEntityList
      header={t('sidebar.chat.header')}
      createTitle={t('sidebar.chat.newChat')}
      onCreate={handleNewChat}
      isLoading={isLoading}
      loadingLabel={t('sidebar.loading')}
      emptyMessage={t('sidebar.chat.noConversations')}
      emptyActionLabel={t('sidebar.chat.startNew')}
      onEmptyAction={handleNewChat}
      items={conversations}
      getItemKey={(conversation) => conversation.id}
      topContent={
        !isReady ? (
          <div className="chat-auth-prompt">
            <p>{t('sidebar.chat.apiKeyNeeded')}</p>
          </div>
        ) : null
      }
      renderItem={(conversation) => (
        <div
          className="chat-list-item"
          onClick={() => handleOpenChat(conversation.id)}
        >
          <div className="chat-item-content">
            <div className="chat-item-title">{conversation.title}</div>
            <div className="chat-item-date">
              {formatSidebarRelativeDate({ dateString: conversation.updatedAt, language, t })}
            </div>
          </div>
          <button
            className="chat-item-delete"
            onClick={(event) => {
              event.stopPropagation();
              handleDeleteChat(conversation.id);
            }}
            title={t('sidebar.chat.deleteConversation')}
          >
            ×
          </button>
        </div>
      )}
    />
  );
};

const ImportList: React.FC = () => {
  const { t, language } = useI18n();
  const { openTab, closeTab, activeProject } = useAppStore();
  const activeProjectId = activeProject?.id;

  const loadDefinitions = useCallback(async (): Promise<ImportDefinitionData[]> => {
    try {
      const defs = await window.electronAPI?.importDefinitions.getAll();
      return defs ?? [];
    } catch (error) {
      console.error('Failed to load import definitions:', error);
      return [];
    }
  }, []);

  const {
    items: definitions,
    setItems: setDefinitions,
    isLoading,
  } = useProjectScopedSidebarData<ImportDefinitionData>({
    load: loadDefinitions,
    activeProjectId,
  });

  // Listen for import definition name updates
  useEffect(() => {
    const unsub = window.electronAPI?.importDefinitions.onNameUpdated((data) => {
      setDefinitions(prev => 
        prev.map(def => 
          def.id === data.definitionId 
            ? { ...def, name: data.name }
            : def
        )
      );
    });

    return () => {
      unsub?.();
    };
  }, []);

  const handleNewDefinition = async () => {
    try {
      const def = await window.electronAPI?.importDefinitions.create();
      if (def) {
        setDefinitions(prev => [def, ...prev]);
        openImportTab(openTab, def.id);
      }
    } catch (error) {
      console.error('Failed to create import definition:', error);
      showToast.error(t('sidebar.import.createFailed'));
    }
  };

  const handleOpenDefinition = (definitionId: string) => {
    openImportTab(openTab, definitionId);
  };

  const handleDeleteDefinition = async (e: React.MouseEvent, definitionId: string) => {
    e.stopPropagation();
    try {
      await window.electronAPI?.importDefinitions.delete(definitionId);
      setDefinitions(prev => prev.filter(d => d.id !== definitionId));
      closeTab(definitionId);
    } catch (error) {
      console.error('Failed to delete import definition:', error);
      showToast.error(t('sidebar.import.deleteFailed'));
    }
  };

  return (
    <SidebarEntityList
      header={t('sidebar.import.header')}
      createTitle={t('sidebar.import.newDefinition')}
      onCreate={handleNewDefinition}
      isLoading={isLoading}
      loadingLabel={t('sidebar.loading')}
      emptyMessage={t('sidebar.import.none')}
      emptyActionLabel={t('sidebar.import.createDefinition')}
      onEmptyAction={handleNewDefinition}
      items={definitions}
      getItemKey={(definition) => definition.id}
      renderItem={(definition) => (
        <div
          className="chat-list-item"
          onClick={() => handleOpenDefinition(definition.id)}
        >
          <div className="chat-item-content">
            <div className="chat-item-title">{definition.name}</div>
            <div className="chat-item-date">
              {formatSidebarRelativeDate({ dateString: definition.updatedAt, language, t })}
            </div>
          </div>
          <button
            className="chat-item-delete"
            onClick={(event) => handleDeleteDefinition(event, definition.id)}
            title={t('sidebar.import.deleteDefinition')}
          >
            ×
          </button>
        </div>
      )}
    />
  );
};

const ScriptsList: React.FC = () => {
  const { t, language } = useI18n();
  const { openTab, activeTabId, closeTab } = useAppStore();
  const activeProjectId = useAppStore((state) => state.activeProject?.id);

  const loadScripts = useCallback(async (): Promise<Array<{ id: string; title: string; updatedAt: string }>> => {
    const items = await window.electronAPI?.scripts.getAll();
    return (items ?? []).map((item) => ({ id: item.id, title: item.title, updatedAt: item.updatedAt }));
  }, []);

  const {
    items: scripts,
    setItems: setScripts,
    isLoading,
    reload: reloadScripts,
  } = useProjectScopedSidebarData<Array<{ id: string; title: string; updatedAt: string }>[number]>({
    load: loadScripts,
    activeProjectId,
    refreshEventName: BDS_EVENT_SCRIPTS_CHANGED,
  });

  const handleCreateScript = async () => {
    try {
      const created = await window.electronAPI?.scripts.create({
        title: t('sidebar.scripts.newScript'),
        kind: 'utility',
        content: 'print("new script")',
        entrypoint: 'render',
        enabled: true,
      });

      if (!created) {
        return;
      }

      setScripts((prev) => [
        { id: created.id, title: created.title, updatedAt: created.updatedAt },
        ...prev.filter((script) => script.id !== created.id),
      ]);
      dispatchWindowEvent(BDS_EVENT_SCRIPTS_CHANGED);
      openScriptTab(openTab, created.id, 'pin');
      void reloadScripts();
    } catch (error) {
      console.error('Failed to create script:', error);
      showToast.error(t('sidebar.scripts.createFailed'));
    }
  };

  const handleDeleteScript = async (event: React.MouseEvent, scriptId: string) => {
    event.stopPropagation();
    try {
      const deleted = await window.electronAPI?.scripts.delete(scriptId);
      if (!deleted) {
        showToast.error(t('sidebar.scripts.deleteFailed'));
        return;
      }
      setScripts((prev) => prev.filter((script) => script.id !== scriptId));
      closeTab(scriptId);
      dispatchWindowEvent(BDS_EVENT_SCRIPTS_CHANGED);
    } catch (error) {
      console.error('Failed to delete script:', error);
      showToast.error(t('sidebar.scripts.deleteFailed'));
    }
  };

  return (
    <SidebarEntityList
      header={t('sidebar.scripts.header')}
      createTitle={t('sidebar.scripts.newScript')}
      onCreate={handleCreateScript}
      isLoading={isLoading}
      loadingLabel={t('sidebar.loading')}
      emptyMessage={t('sidebar.scripts.none')}
      emptyActionLabel={t('sidebar.scripts.createScript')}
      onEmptyAction={handleCreateScript}
      items={scripts}
      getItemKey={(script) => script.id}
      renderItem={(script) => (
        <div
          role="button"
          tabIndex={0}
          aria-label={script.title}
          className={`chat-list-item ${activeTabId === script.id ? 'active' : ''}`}
          onClick={() => openScriptTab(openTab, script.id, 'preview')}
          onDoubleClick={() => openScriptTab(openTab, script.id, 'pin')}
          onKeyDown={(event) => {
            if (event.key === 'Enter') {
              openScriptTab(openTab, script.id, 'pin');
              return;
            }
            if (event.key === ' ') {
              event.preventDefault();
              openScriptTab(openTab, script.id, 'preview');
            }
          }}
        >
          <div className="chat-item-content">
            <div className="chat-item-title">{script.title}</div>
            <div className="chat-item-date">
              {formatSidebarRelativeDate({ dateString: script.updatedAt, language, t })}
            </div>
          </div>
          <button
            className="chat-item-delete"
            onClick={(event) => handleDeleteScript(event, script.id)}
            title={t('sidebar.scripts.deleteScript')}
          >
            ×
          </button>
        </div>
      )}
    />
  );
};

const TemplatesList: React.FC = () => {
  const { t, language } = useI18n();
  const { openTab, activeTabId, closeTab } = useAppStore();
  const activeProjectId = useAppStore((state) => state.activeProject?.id);

  const loadTemplates = useCallback(async (): Promise<Array<{ id: string; title: string; updatedAt: string }>> => {
    const items = await window.electronAPI?.templates.getAll();
    return (items ?? []).map((item) => ({ id: item.id, title: item.title, updatedAt: item.updatedAt }));
  }, []);

  const {
    items: templates,
    setItems: setTemplates,
    isLoading,
    reload: reloadTemplates,
  } = useProjectScopedSidebarData<Array<{ id: string; title: string; updatedAt: string }>[number]>({
    load: loadTemplates,
    activeProjectId,
    refreshEventName: BDS_EVENT_TEMPLATES_CHANGED,
  });

  const handleCreateTemplate = async () => {
    try {
      const created = await window.electronAPI?.templates.create({
        title: t('sidebar.templates.newTemplate'),
        kind: 'post',
        content: '',
        enabled: true,
      });

      if (!created) {
        return;
      }

      setTemplates((prev) => [
        { id: created.id, title: created.title, updatedAt: created.updatedAt },
        ...prev.filter((tmpl) => tmpl.id !== created.id),
      ]);
      dispatchWindowEvent(BDS_EVENT_TEMPLATES_CHANGED);
      openTemplateTab(openTab, created.id, 'pin');
      void reloadTemplates();
    } catch (error) {
      console.error('Failed to create template:', error);
      showToast.error(t('sidebar.templates.createFailed'));
    }
  };

  const handleDeleteTemplate = async (event: React.MouseEvent, templateId: string) => {
    event.stopPropagation();
    try {
      const result = await window.electronAPI?.templates.delete(templateId);
      if (!result) {
        showToast.error(t('sidebar.templates.deleteFailed'));
        return;
      }

      if (!result.deleted && result.references) {
        const { postIds, tagIds } = result.references;
        const confirmed = window.confirm(
          t('sidebar.templates.deleteConfirmWithRefs', {
            postCount: String(postIds.length),
            tagCount: String(tagIds.length),
          }),
        );
        if (!confirmed) {
          return;
        }
        const forceResult = await window.electronAPI?.templates.delete(templateId, { force: true });
        if (!forceResult?.deleted) {
          showToast.error(t('sidebar.templates.deleteFailed'));
          return;
        }
      }

      setTemplates((prev) => prev.filter((tmpl) => tmpl.id !== templateId));
      closeTab(templateId);
      dispatchWindowEvent(BDS_EVENT_TEMPLATES_CHANGED);
    } catch (error) {
      console.error('Failed to delete template:', error);
      showToast.error(t('sidebar.templates.deleteFailed'));
    }
  };

  return (
    <SidebarEntityList
      header={t('sidebar.templates.header')}
      createTitle={t('sidebar.templates.newTemplate')}
      onCreate={handleCreateTemplate}
      isLoading={isLoading}
      loadingLabel={t('sidebar.loading')}
      emptyMessage={t('sidebar.templates.none')}
      emptyActionLabel={t('sidebar.templates.createTemplate')}
      onEmptyAction={handleCreateTemplate}
      items={templates}
      getItemKey={(tmpl) => tmpl.id}
      renderItem={(tmpl) => (
        <div
          role="button"
          tabIndex={0}
          aria-label={tmpl.title}
          className={`chat-list-item ${activeTabId === tmpl.id ? 'active' : ''}`}
          onClick={() => openTemplateTab(openTab, tmpl.id, 'preview')}
          onDoubleClick={() => openTemplateTab(openTab, tmpl.id, 'pin')}
          onKeyDown={(event) => {
            if (event.key === 'Enter') {
              openTemplateTab(openTab, tmpl.id, 'pin');
              return;
            }
            if (event.key === ' ') {
              event.preventDefault();
              openTemplateTab(openTab, tmpl.id, 'preview');
            }
          }}
        >
          <div className="chat-item-content">
            <div className="chat-item-title">{tmpl.title}</div>
            <div className="chat-item-date">
              {formatSidebarRelativeDate({ dateString: tmpl.updatedAt, language, t })}
            </div>
          </div>
          <button
            className="chat-item-delete"
            onClick={(event) => handleDeleteTemplate(event, tmpl.id)}
            title={t('sidebar.templates.deleteTemplate')}
          >
            ×
          </button>
        </div>
      )}
    />
  );
};

export const Sidebar: React.FC = () => {
  const { activeView, sidebarVisible } = useAppStore();

  if (!sidebarVisible) {
    return null;
  }

  const sidebarViewMap: Record<SidebarView, React.ReactNode> = {
    posts: <PostsList mode="posts" isActive={true} />,
    pages: <PostsList mode="pages" isActive={true} />,
    media: <MediaList />,
    scripts: <ScriptsList />,
    templates: <TemplatesList />,
    settings: <SettingsNav />,
    tags: <TagsNav />,
    chat: <ChatList />,
    import: <ImportList />,
    git: <GitSidebar />,
  };

  return (
    <div className="sidebar">
      {sidebarViewMap[activeView]}
    </div>
  );
};
