import { describe, it, expect, vi, beforeEach } from 'vitest'
import { render, screen, fireEvent } from '@testing-library/react'
import { BlockReviewPanel, BlockReviewSummary, type BlockReviewData } from '../BlockReviewPanel'
import type { GridData, GridCell } from '../GridOverlay'

// Mock grid data
const createMockGrid = (rows: number = 3, cols: number = 3): GridData => {
  const cells: GridCell[][] = []
  for (let r = 0; r < rows; r++) {
    const row: GridCell[] = []
    for (let c = 0; c < cols; c++) {
      row.push({
        row: r,
        col: c,
        x: (c / cols) * 100,
        y: (r / rows) * 100,
        width: 100 / cols,
        height: 100 / rows,
        text: r === 0 || c === 0 ? '' : `cell-${r}-${c}`,
        confidence: 0.85,
        status: r === 0 || c === 0 ? 'empty' : 'recognized',
        column_type: c === 1 ? 'english' : c === 2 ? 'german' : 'unknown',
      })
    }
    cells.push(row)
  }

  return {
    rows,
    columns: cols,
    cells,
    column_types: ['unknown', 'english', 'german'],
    column_boundaries: [0, 33.33, 66.66, 100],
    row_boundaries: [0, 33.33, 66.66, 100],
    deskew_angle: 0,
    stats: {
      recognized: 4,
      problematic: 0,
      empty: 5,
      total: 9,
      coverage: 0.44,
    },
  }
}

const createMockMethodResults = () => ({
  vision_llm: {
    vocabulary: [
      { english: 'word1', german: 'Wort1' },
      { english: 'word2', german: 'Wort2' },
    ],
  },
  tesseract: {
    vocabulary: [
      { english: 'word1', german: 'Wort1' },
      { english: 'word2', german: 'Wort2' },
    ],
  },
})

describe('BlockReviewPanel', () => {
  const mockOnBlockChange = vi.fn()
  const mockOnApprove = vi.fn()
  const mockOnCorrect = vi.fn()
  const mockOnSkip = vi.fn()

  beforeEach(() => {
    vi.clearAllMocks()
  })

  it('should render the current block number', () => {
    render(
      <BlockReviewPanel
        grid={createMockGrid()}
        methodResults={createMockMethodResults()}
        currentBlockNumber={5}
        onBlockChange={mockOnBlockChange}
        onApprove={mockOnApprove}
        onCorrect={mockOnCorrect}
        onSkip={mockOnSkip}
        reviewData={{}}
      />
    )

    expect(screen.getByText('Block 5')).toBeInTheDocument()
  })

  it('should display progress percentage', () => {
    const reviewData: Record<number, BlockReviewData> = {
      5: {
        blockNumber: 5,
        cell: createMockGrid().cells[1][1],
        methodResults: [],
        status: 'approved',
        correctedText: 'approved text',
      },
    }

    render(
      <BlockReviewPanel
        grid={createMockGrid()}
        methodResults={createMockMethodResults()}
        currentBlockNumber={5}
        onBlockChange={mockOnBlockChange}
        onApprove={mockOnApprove}
        onCorrect={mockOnCorrect}
        onSkip={mockOnSkip}
        reviewData={reviewData}
      />
    )

    expect(screen.getByText('25%')).toBeInTheDocument()
  })

  it('should show cell position information', () => {
    render(
      <BlockReviewPanel
        grid={createMockGrid()}
        methodResults={createMockMethodResults()}
        currentBlockNumber={5}
        onBlockChange={mockOnBlockChange}
        onApprove={mockOnApprove}
        onCorrect={mockOnCorrect}
        onSkip={mockOnSkip}
        reviewData={{}}
      />
    )

    expect(screen.getByText('Position:')).toBeInTheDocument()
  })

  it('should display method results', () => {
    render(
      <BlockReviewPanel
        grid={createMockGrid()}
        methodResults={createMockMethodResults()}
        currentBlockNumber={5}
        onBlockChange={mockOnBlockChange}
        onApprove={mockOnApprove}
        onCorrect={mockOnCorrect}
        onSkip={mockOnSkip}
        reviewData={{}}
      />
    )

    expect(screen.getByText('Erkannte Texte:')).toBeInTheDocument()
  })

  it('should call onSkip when skip button is clicked', () => {
    render(
      <BlockReviewPanel
        grid={createMockGrid()}
        methodResults={createMockMethodResults()}
        currentBlockNumber={5}
        onBlockChange={mockOnBlockChange}
        onApprove={mockOnApprove}
        onCorrect={mockOnCorrect}
        onSkip={mockOnSkip}
        reviewData={{}}
      />
    )

    fireEvent.click(screen.getByText('Überspringen'))
    expect(mockOnSkip).toHaveBeenCalledWith(5)
  })

  it('should show manual correction button', () => {
    render(
      <BlockReviewPanel
        grid={createMockGrid()}
        methodResults={createMockMethodResults()}
        currentBlockNumber={5}
        onBlockChange={mockOnBlockChange}
        onApprove={mockOnApprove}
        onCorrect={mockOnCorrect}
        onSkip={mockOnSkip}
        reviewData={{}}
      />
    )

    expect(screen.getByText('+ Manuell korrigieren')).toBeInTheDocument()
  })

  it('should show correction input when correction button is clicked', () => {
    render(
      <BlockReviewPanel
        grid={createMockGrid()}
        methodResults={createMockMethodResults()}
        currentBlockNumber={5}
        onBlockChange={mockOnBlockChange}
        onApprove={mockOnApprove}
        onCorrect={mockOnCorrect}
        onSkip={mockOnSkip}
        reviewData={{}}
      />
    )

    fireEvent.click(screen.getByText('+ Manuell korrigieren'))
    expect(screen.getByPlaceholderText('Korrekten Text eingeben...')).toBeInTheDocument()
  })

  it('should call onCorrect when correction is submitted', () => {
    render(
      <BlockReviewPanel
        grid={createMockGrid()}
        methodResults={createMockMethodResults()}
        currentBlockNumber={5}
        onBlockChange={mockOnBlockChange}
        onApprove={mockOnApprove}
        onCorrect={mockOnCorrect}
        onSkip={mockOnSkip}
        reviewData={{}}
      />
    )

    fireEvent.click(screen.getByText('+ Manuell korrigieren'))
    const input = screen.getByPlaceholderText('Korrekten Text eingeben...')
    fireEvent.change(input, { target: { value: 'corrected text' } })
    fireEvent.click(screen.getByText('Übernehmen'))

    expect(mockOnCorrect).toHaveBeenCalledWith(5, 'corrected text')
  })

  it('should show approved status when block is approved', () => {
    const reviewData: Record<number, BlockReviewData> = {
      5: {
        blockNumber: 5,
        cell: createMockGrid().cells[1][1],
        methodResults: [],
        status: 'approved',
        correctedText: 'approved text',
      },
    }

    render(
      <BlockReviewPanel
        grid={createMockGrid()}
        methodResults={createMockMethodResults()}
        currentBlockNumber={5}
        onBlockChange={mockOnBlockChange}
        onApprove={mockOnApprove}
        onCorrect={mockOnCorrect}
        onSkip={mockOnSkip}
        reviewData={reviewData}
      />
    )

    expect(screen.getByText(/Freigegeben:/)).toBeInTheDocument()
  })

  it('should disable previous button on first block', () => {
    render(
      <BlockReviewPanel
        grid={createMockGrid()}
        methodResults={createMockMethodResults()}
        currentBlockNumber={5}
        onBlockChange={mockOnBlockChange}
        onApprove={mockOnApprove}
        onCorrect={mockOnCorrect}
        onSkip={mockOnSkip}
        reviewData={{}}
      />
    )

    const prevButton = screen.getByText('Zurück').closest('button')
    expect(prevButton).toBeDisabled()
  })

  it('should show empty message when no blocks available', () => {
    const emptyGrid: GridData = {
      ...createMockGrid(),
      cells: [[{
        row: 0,
        col: 0,
        x: 0,
        y: 0,
        width: 100,
        height: 100,
        text: '',
        confidence: 0,
        status: 'empty'
      }]],
    }

    render(
      <BlockReviewPanel
        grid={emptyGrid}
        methodResults={{}}
        currentBlockNumber={1}
        onBlockChange={mockOnBlockChange}
        onApprove={mockOnApprove}
        onCorrect={mockOnCorrect}
        onSkip={mockOnSkip}
        reviewData={{}}
      />
    )

    expect(screen.getByText('Keine Blöcke zum Überprüfen')).toBeInTheDocument()
  })
})

describe('BlockReviewSummary', () => {
  const mockOnBlockClick = vi.fn()

  beforeEach(() => {
    vi.clearAllMocks()
  })

  it('should display summary statistics', () => {
    const reviewData: Record<number, BlockReviewData> = {
      1: { blockNumber: 1, cell: {} as GridCell, methodResults: [], status: 'approved', correctedText: 'text1' },
      2: { blockNumber: 2, cell: {} as GridCell, methodResults: [], status: 'corrected', correctedText: 'text2' },
      3: { blockNumber: 3, cell: {} as GridCell, methodResults: [], status: 'skipped' },
    }

    render(
      <BlockReviewSummary
        reviewData={reviewData}
        totalBlocks={5}
        onBlockClick={mockOnBlockClick}
      />
    )

    expect(screen.getByText('Überprüfungsübersicht')).toBeInTheDocument()
    expect(screen.getByText('1')).toBeInTheDocument() // approved count
    expect(screen.getByText('Freigegeben')).toBeInTheDocument()
    expect(screen.getByText('Korrigiert')).toBeInTheDocument()
    expect(screen.getByText('Übersprungen')).toBeInTheDocument()
    expect(screen.getByText('Ausstehend')).toBeInTheDocument()
  })

  it('should call onBlockClick when a block is clicked', () => {
    const reviewData: Record<number, BlockReviewData> = {
      5: { blockNumber: 5, cell: {} as GridCell, methodResults: [], status: 'approved', correctedText: 'text' },
    }

    render(
      <BlockReviewSummary
        reviewData={reviewData}
        totalBlocks={10}
        onBlockClick={mockOnBlockClick}
      />
    )

    fireEvent.click(screen.getByText('Block 5'))
    expect(mockOnBlockClick).toHaveBeenCalledWith(5)
  })

  it('should show correct counts for each status', () => {
    const reviewData: Record<number, BlockReviewData> = {
      1: { blockNumber: 1, cell: {} as GridCell, methodResults: [], status: 'approved', correctedText: 't1' },
      2: { blockNumber: 2, cell: {} as GridCell, methodResults: [], status: 'approved', correctedText: 't2' },
      3: { blockNumber: 3, cell: {} as GridCell, methodResults: [], status: 'corrected', correctedText: 't3' },
    }

    render(
      <BlockReviewSummary
        reviewData={reviewData}
        totalBlocks={5}
        onBlockClick={mockOnBlockClick}
      />
    )

    // 2 approved, 1 corrected, 0 skipped, 2 pending
    const approvedCount = screen.getAllByText('2')[0]
    expect(approvedCount).toBeInTheDocument()
  })

  it('should truncate long corrected text', () => {
    const reviewData: Record<number, BlockReviewData> = {
      1: {
        blockNumber: 1,
        cell: {} as GridCell,
        methodResults: [],
        status: 'approved',
        correctedText: 'This is a very long text that should be truncated'
      },
    }

    render(
      <BlockReviewSummary
        reviewData={reviewData}
        totalBlocks={1}
        onBlockClick={mockOnBlockClick}
      />
    )

    expect(screen.getByText(/This is a very long t\.\.\./)).toBeInTheDocument()
  })
})
