/**
 * Tests for postGrouping utility
 * 
 * Tests the groupPostsByStatus function that ensures posts are correctly
 * grouped by status, with stale cached filter results freshened from store data.
 */

import { describe, it, expect, beforeEach } from 'vitest';
import { groupPostsByStatus } from '../../../src/renderer/utils/postGrouping';
import type { PostData } from '../../../src/renderer/store/appStore';

// Factory function for creating test posts
function createTestPost(overrides: Partial<PostData>): PostData {
  return {
    id: 'test-id',
    projectId: 'project-1',
    title: 'Test Post',
    slug: 'test-post',
    excerpt: 'Test excerpt',
    content: 'Test content',
    status: 'draft',
    author: 'Test Author',
    createdAt: '2024-01-01T00:00:00Z',
    updatedAt: '2024-01-01T00:00:00Z',
    tags: [],
    categories: [],
    ...overrides,
  };
}

describe('groupPostsByStatus', () => {
  let draftPost: PostData;
  let publishedPost: PostData;
  let archivedPost: PostData;

  beforeEach(() => {
    draftPost = createTestPost({ id: 'draft-1', status: 'draft', title: 'Draft Post' });
    publishedPost = createTestPost({ id: 'published-1', status: 'published', title: 'Published Post', publishedAt: '2024-01-01T00:00:00Z' });
    archivedPost = createTestPost({ id: 'archived-1', status: 'archived', title: 'Archived Post' });
  });

  describe('without filters (filteredPosts is null)', () => {
    it('should group all posts by their status', () => {
      const storePosts = [draftPost, publishedPost, archivedPost];
      
      const result = groupPostsByStatus(storePosts, null);
      
      expect(result.draft).toHaveLength(1);
      expect(result.draft[0].id).toBe('draft-1');
      
      expect(result.published).toHaveLength(1);
      expect(result.published[0].id).toBe('published-1');
      
      expect(result.archived).toHaveLength(1);
      expect(result.archived[0].id).toBe('archived-1');
    });

    it('should return empty arrays when no posts exist', () => {
      const result = groupPostsByStatus([], null);
      
      expect(result.draft).toHaveLength(0);
      expect(result.published).toHaveLength(0);
      expect(result.archived).toHaveLength(0);
    });

    it('should handle multiple posts with the same status', () => {
      const draft2 = createTestPost({ id: 'draft-2', status: 'draft' });
      const published2 = createTestPost({ id: 'published-2', status: 'published' });
      const storePosts = [draftPost, draft2, publishedPost, published2];
      
      const result = groupPostsByStatus(storePosts, null);
      
      expect(result.draft).toHaveLength(2);
      expect(result.published).toHaveLength(2);
      expect(result.archived).toHaveLength(0);
    });
  });

  describe('with active filters (filteredPosts is not null)', () => {
    it('should use filtered posts for published/archived, but always use store for drafts', () => {
      const storePosts = [draftPost, publishedPost, archivedPost];
      // Filter only returns the published post
      const filteredPosts = [publishedPost];
      
      const result = groupPostsByStatus(storePosts, filteredPosts);
      
      // Drafts always come from store
      expect(result.draft).toHaveLength(1);
      expect(result.draft[0].id).toBe('draft-1');
      
      // Published/archived come from filtered list
      expect(result.published).toHaveLength(1);
      expect(result.published[0].id).toBe('published-1');
      expect(result.archived).toHaveLength(0);
    });
  });

  describe('freshening stale cached data (the bug fix)', () => {
    it('should NOT show post in published when its status changed to draft in store', () => {
      // Initial state: post is published
      const originalPublishedPost = createTestPost({ 
        id: 'post-1', 
        status: 'published',
        title: 'My Post' 
      });
      
      // User edits the post, changing status to draft in the store
      const updatedPost = createTestPost({ 
        id: 'post-1', 
        status: 'draft',  // Changed!
        title: 'My Post' 
      });
      
      // Store has the updated version
      const storePosts = [updatedPost];
      
      // Filter cache still has the old version with 'published' status
      const staleFilteredPosts = [originalPublishedPost];
      
      const result = groupPostsByStatus(storePosts, staleFilteredPosts);
      
      // Post should appear in drafts (from fresh store data)
      expect(result.draft).toHaveLength(1);
      expect(result.draft[0].id).toBe('post-1');
      expect(result.draft[0].status).toBe('draft');
      
      // Post should NOT appear in published (stale data should be freshened)
      expect(result.published).toHaveLength(0);
    });

    it('should freshen all properties from store, not just status', () => {
      // Store has updated post
      const storePost = createTestPost({ 
        id: 'post-1', 
        status: 'published',
        title: 'Updated Title',
        content: 'Updated content'
      });
      
      // Cache has stale data
      const cachedPost = createTestPost({ 
        id: 'post-1', 
        status: 'published',
        title: 'Old Title',
        content: 'Old content'
      });
      
      const result = groupPostsByStatus([storePost], [cachedPost]);
      
      expect(result.published).toHaveLength(1);
      expect(result.published[0].title).toBe('Updated Title');
      expect(result.published[0].content).toBe('Updated content');
    });

    it('should keep cached post if not found in store (e.g., paginated out)', () => {
      // Store doesn't have the post (paginated out)
      const storePosts: PostData[] = [];
      
      // Cache still has the post from a search result
      const cachedPost = createTestPost({ 
        id: 'post-1', 
        status: 'published',
        title: 'Paginated Post'
      });
      
      const result = groupPostsByStatus(storePosts, [cachedPost]);
      
      // Should keep the cached version since it's not in store
      expect(result.published).toHaveLength(1);
      expect(result.published[0].title).toBe('Paginated Post');
    });

    it('should handle mix of fresh and stale posts in filter results', () => {
      // Store has two posts
      const freshPost1 = createTestPost({ id: 'post-1', status: 'published', title: 'Fresh 1' });
      const freshPost2 = createTestPost({ id: 'post-2', status: 'draft', title: 'Fresh 2' }); // Changed to draft!
      
      // Cache has stale versions
      const stalePost1 = createTestPost({ id: 'post-1', status: 'published', title: 'Stale 1' });
      const stalePost2 = createTestPost({ id: 'post-2', status: 'published', title: 'Stale 2' }); // Was published
      const cachedOnlyPost = createTestPost({ id: 'post-3', status: 'archived', title: 'Cached Only' });
      
      const result = groupPostsByStatus(
        [freshPost1, freshPost2],
        [stalePost1, stalePost2, cachedOnlyPost]
      );
      
      // post-1: freshened from store, still published
      expect(result.published).toHaveLength(1);
      expect(result.published[0].id).toBe('post-1');
      expect(result.published[0].title).toBe('Fresh 1'); // Freshened!
      
      // post-2: freshened from store, now draft - appears in drafts
      expect(result.draft).toHaveLength(1);
      expect(result.draft[0].id).toBe('post-2');
      expect(result.draft[0].status).toBe('draft');
      
      // post-3: not in store, kept from cache
      expect(result.archived).toHaveLength(1);
      expect(result.archived[0].id).toBe('post-3');
    });
  });

  describe('edge cases', () => {
    it('should handle empty filter results', () => {
      const storePosts = [draftPost, publishedPost];
      
      const result = groupPostsByStatus(storePosts, []);
      
      // Empty filter returns no published/archived
      expect(result.draft).toHaveLength(1); // Drafts always from store
      expect(result.published).toHaveLength(0);
      expect(result.archived).toHaveLength(0);
    });

    it('should not create duplicates when same post is in store and filter', () => {
      const post = createTestPost({ id: 'post-1', status: 'published' });
      
      const result = groupPostsByStatus([post], [post]);
      
      expect(result.published).toHaveLength(1);
    });
  });
});
