/**
 * Integration Test: Pipeline Data Source Store Composition
 *
 * Tests cross-slice interactions in the pipeline data source Zustand store.
 * The unit-level slice specs test each slice in isolation.
 * This integration test verifies:
 *   - Store initialization produces correct defaults across all slices
 *   - Cross-slice coordination (e.g. credential shared across slices)
 *   - State isolation: changes in one slice do not affect others
 *   - Full workflow simulation through credential → source → data path
 */

import type { NotionPage } from '@/models/common'
import type { CrawlResultItem, FileItem } from '@/models/datasets'
import type { OnlineDriveFile } from '@/models/pipeline'
import { createDataSourceStore } from '@/app/components/datasets/documents/create-from-pipeline/data-source/store'
import { CrawlStep } from '@/models/datasets'
import { OnlineDriveFileType } from '@/models/pipeline'

// --- Factory functions ---

const createFileItem = (id: string): FileItem => ({
  fileID: id,
  file: { id, name: `${id}.txt`, size: 1024 } as FileItem['file'],
  progress: 100,
})

const createCrawlResultItem = (url: string, title?: string): CrawlResultItem => ({
  title: title ?? `Page: ${url}`,
  markdown: `# ${title ?? url}\n\nContent for ${url}`,
  description: `Description for ${url}`,
  source_url: url,
})

const createOnlineDriveFile = (id: string, name: string, type = OnlineDriveFileType.file): OnlineDriveFile => ({
  id,
  name,
  size: 2048,
  type,
})

const createNotionPage = (pageId: string): NotionPage => ({
  page_id: pageId,
  page_name: `Page ${pageId}`,
  page_icon: null,
  is_bound: true,
  parent_id: 'parent-1',
  type: 'page',
  workspace_id: 'ws-1',
})

describe('Pipeline Data Source Store Composition - Cross-Slice Integration', () => {
  describe('Store Initialization → All Slices Have Correct Defaults', () => {
    it('should create a store with all five slices combined', () => {
      const store = createDataSourceStore()
      const state = store.getState()

      // Common slice defaults
      expect(state.currentCredentialId).toBe('')
      expect(state.currentNodeIdRef.current).toBe('')

      // Local file slice defaults
      expect(state.localFileList).toEqual([])
      expect(state.currentLocalFile).toBeUndefined()

      // Online document slice defaults
      expect(state.documentsData).toEqual([])
      expect(state.onlineDocuments).toEqual([])
      expect(state.searchValue).toBe('')
      expect(state.selectedPagesId).toEqual(new Set())

      // Website crawl slice defaults
      expect(state.websitePages).toEqual([])
      expect(state.step).toBe(CrawlStep.init)
      expect(state.previewIndex).toBe(-1)

      // Online drive slice defaults
      expect(state.breadcrumbs).toEqual([])
      expect(state.prefix).toEqual([])
      expect(state.keywords).toBe('')
      expect(state.selectedFileIds).toEqual([])
      expect(state.onlineDriveFileList).toEqual([])
      expect(state.bucket).toBe('')
      expect(state.hasBucket).toBe(false)
    })
  })

  describe('Cross-Slice Coordination: Shared Credential', () => {
    it('should set credential that is accessible from the common slice', () => {
      const store = createDataSourceStore()

      store.getState().setCurrentCredentialId('cred-abc-123')

      expect(store.getState().currentCredentialId).toBe('cred-abc-123')
    })

    it('should allow credential update independently of all other slices', () => {
      const store = createDataSourceStore()

      store.getState().setLocalFileList([createFileItem('f1')])
      store.getState().setCurrentCredentialId('cred-xyz')

      expect(store.getState().currentCredentialId).toBe('cred-xyz')
      expect(store.getState().localFileList).toHaveLength(1)
    })
  })

  describe('Local File Workflow: Set Files → Verify List → Clear', () => {
    it('should set and retrieve local file list', () => {
      const store = createDataSourceStore()
      const files = [createFileItem('f1'), createFileItem('f2'), createFileItem('f3')]

      store.getState().setLocalFileList(files)

      expect(store.getState().localFileList).toHaveLength(3)
      expect(store.getState().localFileList[0]!.fileID).toBe('f1')
      expect(store.getState().localFileList[2]!.fileID).toBe('f3')
    })

    it('should update preview ref when setting file list', () => {
      const store = createDataSourceStore()
      const files = [createFileItem('f-preview')]

      store.getState().setLocalFileList(files)

      expect(store.getState().previewLocalFileRef.current).toBeDefined()
    })

    it('should clear files by setting empty list', () => {
      const store = createDataSourceStore()

      store.getState().setLocalFileList([createFileItem('f1')])
      expect(store.getState().localFileList).toHaveLength(1)

      store.getState().setLocalFileList([])
      expect(store.getState().localFileList).toHaveLength(0)
    })

    it('should set and clear current local file selection', () => {
      const store = createDataSourceStore()
      const file = { id: 'current-file', name: 'current.txt' } as FileItem['file']

      store.getState().setCurrentLocalFile(file)
      expect(store.getState().currentLocalFile).toBeDefined()
      expect(store.getState().currentLocalFile?.id).toBe('current-file')

      store.getState().setCurrentLocalFile(undefined)
      expect(store.getState().currentLocalFile).toBeUndefined()
    })
  })

  describe('Online Document Workflow: Set Documents → Select Pages → Verify', () => {
    it('should set documents data and online documents', () => {
      const store = createDataSourceStore()
      const pages = [createNotionPage('page-1'), createNotionPage('page-2')]

      store.getState().setOnlineDocuments(pages)

      expect(store.getState().onlineDocuments).toHaveLength(2)
      expect(store.getState().onlineDocuments[0]!.page_id).toBe('page-1')
    })

    it('should update preview ref when setting online documents', () => {
      const store = createDataSourceStore()
      const pages = [createNotionPage('page-preview')]

      store.getState().setOnlineDocuments(pages)

      expect(store.getState().previewOnlineDocumentRef.current).toBeDefined()
      expect(store.getState().previewOnlineDocumentRef.current?.page_id).toBe('page-preview')
    })

    it('should track selected page IDs', () => {
      const store = createDataSourceStore()
      const pages = [createNotionPage('p1'), createNotionPage('p2'), createNotionPage('p3')]

      store.getState().setOnlineDocuments(pages)
      store.getState().setSelectedPagesId(new Set(['p1', 'p3']))

      expect(store.getState().selectedPagesId.size).toBe(2)
      expect(store.getState().selectedPagesId.has('p1')).toBe(true)
      expect(store.getState().selectedPagesId.has('p2')).toBe(false)
      expect(store.getState().selectedPagesId.has('p3')).toBe(true)
    })

    it('should manage search value for filtering documents', () => {
      const store = createDataSourceStore()

      store.getState().setSearchValue('meeting notes')

      expect(store.getState().searchValue).toBe('meeting notes')
    })

    it('should set and clear current document selection', () => {
      const store = createDataSourceStore()
      const page = createNotionPage('current-page')

      store.getState().setCurrentDocument(page)
      expect(store.getState().currentDocument?.page_id).toBe('current-page')

      store.getState().setCurrentDocument(undefined)
      expect(store.getState().currentDocument).toBeUndefined()
    })
  })

  describe('Website Crawl Workflow: Set Pages → Track Step → Preview', () => {
    it('should set website pages and update preview ref', () => {
      const store = createDataSourceStore()
      const pages = [
        createCrawlResultItem('https://example.com'),
        createCrawlResultItem('https://example.com/about'),
      ]

      store.getState().setWebsitePages(pages)

      expect(store.getState().websitePages).toHaveLength(2)
      expect(store.getState().previewWebsitePageRef.current?.source_url).toBe('https://example.com')
    })

    it('should manage crawl step transitions', () => {
      const store = createDataSourceStore()

      expect(store.getState().step).toBe(CrawlStep.init)

      store.getState().setStep(CrawlStep.running)
      expect(store.getState().step).toBe(CrawlStep.running)

      store.getState().setStep(CrawlStep.finished)
      expect(store.getState().step).toBe(CrawlStep.finished)
    })

    it('should set crawl result with data and timing', () => {
      const store = createDataSourceStore()
      const result = {
        data: [createCrawlResultItem('https://test.com')],
        time_consuming: 3.5,
      }

      store.getState().setCrawlResult(result)

      expect(store.getState().crawlResult?.data).toHaveLength(1)
      expect(store.getState().crawlResult?.time_consuming).toBe(3.5)
    })

    it('should manage preview index for page navigation', () => {
      const store = createDataSourceStore()

      store.getState().setPreviewIndex(2)
      expect(store.getState().previewIndex).toBe(2)

      store.getState().setPreviewIndex(-1)
      expect(store.getState().previewIndex).toBe(-1)
    })

    it('should set and clear current website selection', () => {
      const store = createDataSourceStore()
      const page = createCrawlResultItem('https://current.com')

      store.getState().setCurrentWebsite(page)
      expect(store.getState().currentWebsite?.source_url).toBe('https://current.com')

      store.getState().setCurrentWebsite(undefined)
      expect(store.getState().currentWebsite).toBeUndefined()
    })
  })

  describe('Online Drive Workflow: Breadcrumbs → File Selection → Navigation', () => {
    it('should manage breadcrumb navigation', () => {
      const store = createDataSourceStore()

      store.getState().setBreadcrumbs(['root', 'folder-a', 'subfolder'])

      expect(store.getState().breadcrumbs).toEqual(['root', 'folder-a', 'subfolder'])
    })

    it('should support breadcrumb push/pop pattern', () => {
      const store = createDataSourceStore()

      store.getState().setBreadcrumbs(['root'])
      store.getState().setBreadcrumbs([...store.getState().breadcrumbs, 'level-1'])
      store.getState().setBreadcrumbs([...store.getState().breadcrumbs, 'level-2'])

      expect(store.getState().breadcrumbs).toEqual(['root', 'level-1', 'level-2'])

      // Pop back one level
      store.getState().setBreadcrumbs(store.getState().breadcrumbs.slice(0, -1))
      expect(store.getState().breadcrumbs).toEqual(['root', 'level-1'])
    })

    it('should manage file list and selection', () => {
      const store = createDataSourceStore()
      const files = [
        createOnlineDriveFile('drive-1', 'report.pdf'),
        createOnlineDriveFile('drive-2', 'data.csv'),
        createOnlineDriveFile('drive-3', 'images', OnlineDriveFileType.folder),
      ]

      store.getState().setOnlineDriveFileList(files)
      expect(store.getState().onlineDriveFileList).toHaveLength(3)

      store.getState().setSelectedFileIds(['drive-1', 'drive-2'])
      expect(store.getState().selectedFileIds).toEqual(['drive-1', 'drive-2'])
    })

    it('should update preview ref when selecting files', () => {
      const store = createDataSourceStore()
      const files = [
        createOnlineDriveFile('drive-a', 'file-a.txt'),
        createOnlineDriveFile('drive-b', 'file-b.txt'),
      ]

      store.getState().setOnlineDriveFileList(files)
      store.getState().setSelectedFileIds(['drive-b'])

      expect(store.getState().previewOnlineDriveFileRef.current?.id).toBe('drive-b')
    })

    it('should manage bucket and prefix for S3-like navigation', () => {
      const store = createDataSourceStore()

      store.getState().setBucket('my-data-bucket')
      store.getState().setPrefix(['data', '2024'])
      store.getState().setHasBucket(true)

      expect(store.getState().bucket).toBe('my-data-bucket')
      expect(store.getState().prefix).toEqual(['data', '2024'])
      expect(store.getState().hasBucket).toBe(true)
    })

    it('should manage keywords for search filtering', () => {
      const store = createDataSourceStore()

      store.getState().setKeywords('quarterly report')
      expect(store.getState().keywords).toBe('quarterly report')
    })
  })

  describe('State Isolation: Changes to One Slice Do Not Affect Others', () => {
    it('should keep local file state independent from online document state', () => {
      const store = createDataSourceStore()

      store.getState().setLocalFileList([createFileItem('local-1')])
      store.getState().setOnlineDocuments([createNotionPage('notion-1')])

      expect(store.getState().localFileList).toHaveLength(1)
      expect(store.getState().onlineDocuments).toHaveLength(1)

      // Clearing local files should not affect online documents
      store.getState().setLocalFileList([])
      expect(store.getState().localFileList).toHaveLength(0)
      expect(store.getState().onlineDocuments).toHaveLength(1)
    })

    it('should keep website crawl state independent from online drive state', () => {
      const store = createDataSourceStore()

      store.getState().setWebsitePages([createCrawlResultItem('https://site.com')])
      store.getState().setOnlineDriveFileList([createOnlineDriveFile('d1', 'file.txt')])

      expect(store.getState().websitePages).toHaveLength(1)
      expect(store.getState().onlineDriveFileList).toHaveLength(1)

      // Clearing website pages should not affect drive files
      store.getState().setWebsitePages([])
      expect(store.getState().websitePages).toHaveLength(0)
      expect(store.getState().onlineDriveFileList).toHaveLength(1)
    })

    it('should create fully independent store instances', () => {
      const storeA = createDataSourceStore()
      const storeB = createDataSourceStore()

      storeA.getState().setCurrentCredentialId('cred-A')
      storeA.getState().setLocalFileList([createFileItem('fa-1')])

      expect(storeA.getState().currentCredentialId).toBe('cred-A')
      expect(storeB.getState().currentCredentialId).toBe('')
      expect(storeB.getState().localFileList).toEqual([])
    })
  })

  describe('Full Workflow Simulation: Credential → Source → Data → Verify', () => {
    it('should support a complete local file upload workflow', () => {
      const store = createDataSourceStore()

      // Step 1: Set credential
      store.getState().setCurrentCredentialId('upload-cred-1')

      // Step 2: Set file list
      const files = [createFileItem('upload-1'), createFileItem('upload-2')]
      store.getState().setLocalFileList(files)

      // Step 3: Select current file for preview
      store.getState().setCurrentLocalFile(files[0]!.file)

      // Verify all state is consistent
      expect(store.getState().currentCredentialId).toBe('upload-cred-1')
      expect(store.getState().localFileList).toHaveLength(2)
      expect(store.getState().currentLocalFile?.id).toBe('upload-1')
      expect(store.getState().previewLocalFileRef.current).toBeDefined()
    })

    it('should support a complete website crawl workflow', () => {
      const store = createDataSourceStore()

      // Step 1: Set credential
      store.getState().setCurrentCredentialId('crawl-cred-1')

      // Step 2: Init crawl
      store.getState().setStep(CrawlStep.running)

      // Step 3: Crawl completes with results
      const crawledPages = [
        createCrawlResultItem('https://docs.example.com/guide'),
        createCrawlResultItem('https://docs.example.com/api'),
        createCrawlResultItem('https://docs.example.com/faq'),
      ]
      store.getState().setCrawlResult({ data: crawledPages, time_consuming: 12.5 })
      store.getState().setStep(CrawlStep.finished)

      // Step 4: Set website pages from results
      store.getState().setWebsitePages(crawledPages)

      // Step 5: Set preview
      store.getState().setPreviewIndex(1)

      // Verify all state
      expect(store.getState().currentCredentialId).toBe('crawl-cred-1')
      expect(store.getState().step).toBe(CrawlStep.finished)
      expect(store.getState().websitePages).toHaveLength(3)
      expect(store.getState().crawlResult?.time_consuming).toBe(12.5)
      expect(store.getState().previewIndex).toBe(1)
      expect(store.getState().previewWebsitePageRef.current?.source_url).toBe('https://docs.example.com/guide')
    })

    it('should support a complete online drive navigation workflow', () => {
      const store = createDataSourceStore()

      // Step 1: Set credential
      store.getState().setCurrentCredentialId('drive-cred-1')

      // Step 2: Set bucket
      store.getState().setBucket('company-docs')
      store.getState().setHasBucket(true)

      // Step 3: Navigate into folders
      store.getState().setBreadcrumbs(['company-docs'])
      store.getState().setPrefix(['projects'])
      const folderFiles = [
        createOnlineDriveFile('proj-1', 'project-alpha', OnlineDriveFileType.folder),
        createOnlineDriveFile('proj-2', 'project-beta', OnlineDriveFileType.folder),
        createOnlineDriveFile('readme', 'README.md', OnlineDriveFileType.file),
      ]
      store.getState().setOnlineDriveFileList(folderFiles)

      // Step 4: Navigate deeper
      store.getState().setBreadcrumbs([...store.getState().breadcrumbs, 'project-alpha'])
      store.getState().setPrefix([...store.getState().prefix, 'project-alpha'])

      // Step 5: Select files
      store.getState().setOnlineDriveFileList([
        createOnlineDriveFile('doc-1', 'spec.pdf'),
        createOnlineDriveFile('doc-2', 'design.fig'),
      ])
      store.getState().setSelectedFileIds(['doc-1'])

      // Verify full state
      expect(store.getState().currentCredentialId).toBe('drive-cred-1')
      expect(store.getState().bucket).toBe('company-docs')
      expect(store.getState().breadcrumbs).toEqual(['company-docs', 'project-alpha'])
      expect(store.getState().prefix).toEqual(['projects', 'project-alpha'])
      expect(store.getState().onlineDriveFileList).toHaveLength(2)
      expect(store.getState().selectedFileIds).toEqual(['doc-1'])
      expect(store.getState().previewOnlineDriveFileRef.current?.name).toBe('spec.pdf')
    })
  })
})
