import React from 'react'
import { render, fireEvent, waitFor } from '@testing-library/react-native'
import { View, Text } from 'react-native'
import GenerateVideoScreen from './generateVideo'

// Mock expo-router
jest.mock('expo-router', () => ({
  useRouter: jest.fn(() => ({
    back: jest.fn(),
  })),
  useLocalSearchParams: jest.fn(),
}))

// Mock react-i18next
jest.mock('react-i18next', () => ({
  useTranslation: jest.fn(() => ({
    t: (key: string) => key,
  })),
}))

// Mock expo-status-bar
jest.mock('expo-status-bar', () => ({
  StatusBar: 'StatusBar',
}))

// Mock react-native-safe-area-context
jest.mock('react-native-safe-area-context', () => ({
  SafeAreaView: ({ children }: { children: React.ReactNode }) => (
    <View>{children}</View>
  ),
}))

// Mock expo-linear-gradient
jest.mock('expo-linear-gradient', () => ({
  LinearGradient: 'LinearGradient',
}))

// Mock expo-image
jest.mock('expo-image', () => ({
  Image: 'Image',
}))

// Mock components
jest.mock('@/components/icon', () => ({
  LeftArrowIcon: 'LeftArrowIcon',
  UploadIcon: 'UploadIcon',
  WhitePointsIcon: 'WhitePointsIcon',
}))

jest.mock('@/components/drawer/UploadReferenceImageDrawer', () => ({
  __esModule: true,
  default: 'UploadReferenceImageDrawer',
}))

jest.mock('@/components/ui', () => ({
  StartGeneratingNotification: 'StartGeneratingNotification',
}))

jest.mock('@/components/ui/Toast', () => ({
  __esModule: true,
  default: {
    show: jest.fn(),
    showLoading: jest.fn(),
    hideLoading: jest.fn(),
  },
}))

// Mock hooks
jest.mock('@/hooks/use-template-actions', () => ({
  useTemplateActions: jest.fn(() => ({
    runTemplate: jest.fn().mockResolvedValue({ generationId: 'gen-123' }),
    loading: false,
    error: null,
  })),
}))

jest.mock('@/hooks/use-template-detail', () => ({
  useTemplateDetail: jest.fn(() => ({
    data: undefined,
    loading: false,
    error: null,
    execute: jest.fn(),
  })),
}))

jest.mock('@/lib/uploadFile', () => ({
  uploadFile: jest.fn().mockResolvedValue('https://example.com/uploaded.jpg'),
}))

import { useRouter, useLocalSearchParams } from 'expo-router'
import { useTemplateActions } from '@/hooks/use-template-actions'
import { useTemplateDetail } from '@/hooks/use-template-detail'
import { uploadFile } from '@/lib/uploadFile'
import Toast from '@/components/ui/Toast'

const mockUseRouter = useRouter as jest.MockedFunction<typeof useRouter>
const mockUseLocalSearchParams = useLocalSearchParams as jest.MockedFunction<typeof useLocalSearchParams>
const mockUseTemplateActions = useTemplateActions as jest.MockedFunction<typeof useTemplateActions>
const mockUseTemplateDetail = useTemplateDetail as jest.MockedFunction<typeof useTemplateDetail>

describe('GenerateVideo Screen', () => {
  const mockTemplateDetail = {
    id: 'template-123',
    title: 'Test Template',
    titleEn: 'Test Template',
    thumbnailUrl: 'https://example.com/thumbnail.jpg',
    coverImageUrl: 'https://example.com/cover.jpg',
    price: 10,
    formSchema: {
      startNodes: [
        {
          id: 'node_1',
          type: 'text',
        },
        {
          id: 'node_2',
          type: 'image',
        },
      ],
    },
  }

  beforeEach(() => {
    jest.clearAllMocks()
    mockUseLocalSearchParams.mockReturnValue({ templateId: 'template-123' } as any)
  })

  describe('Data Fetching', () => {
    it('should fetch template detail on mount when templateId is provided', () => {
      const mockExecute = jest.fn()

      mockUseTemplateDetail.mockReturnValue({
        data: undefined,
        loading: false,
        error: null,
        execute: mockExecute,
      } as any)

      render(<GenerateVideoScreen />)

      expect(mockExecute).toHaveBeenCalledWith({ id: 'template-123' })
    })

    it('should not fetch template detail when templateId is not provided', () => {
      const mockExecute = jest.fn()

      mockUseLocalSearchParams.mockReturnValue({} as any)

      mockUseTemplateDetail.mockReturnValue({
        data: undefined,
        loading: false,
        error: null,
        execute: mockExecute,
      } as any)

      render(<GenerateVideoScreen />)

      expect(mockExecute).not.toHaveBeenCalled()
    })

    it('should set previewImageUri when template detail is loaded', () => {
      mockUseTemplateDetail.mockReturnValue({
        data: mockTemplateDetail,
        loading: false,
        error: null,
        execute: jest.fn(),
      } as any)

      render(<GenerateVideoScreen />)

      // Component should render without errors
      // previewImageUri is internal state, so we verify through UI
    })

    it('should handle template loading state', () => {
      mockUseTemplateDetail.mockReturnValue({
        data: undefined,
        loading: true,
        error: null,
        execute: jest.fn(),
      } as any)

      const { getByText } = render(<GenerateVideoScreen />)

      // Should show template title area
      expect(getByText('generateVideo.uploadReference')).toBeTruthy()
    })

    it('should handle template error state', () => {
      mockUseTemplateDetail.mockReturnValue({
        data: undefined,
        loading: false,
        error: { message: 'Failed to load template' },
        execute: jest.fn(),
      } as any)

      const { queryByText } = render(<GenerateVideoScreen />)

      // Should still render the UI if template was loaded before error
      // or show empty state
      expect(queryByText('generateVideo.uploadReference')).toBeTruthy()
    })
  })

  describe('Form Rendering', () => {
    it('should display template title when loaded', () => {
      mockUseTemplateDetail.mockReturnValue({
        data: mockTemplateDetail,
        loading: false,
        error: null,
        execute: jest.fn(),
      } as any)

      const { getAllByText } = render(<GenerateVideoScreen />)

      const titles = getAllByText('Test Template')
      expect(titles.length).toBeGreaterThan(0)
    })

    it('should display template thumbnail', () => {
      mockUseTemplateDetail.mockReturnValue({
        data: mockTemplateDetail,
        loading: false,
        error: null,
        execute: jest.fn(),
      } as any)

      const { getByText } = render(<GenerateVideoScreen />)

      expect(getByText('generateVideo.uploadReference')).toBeTruthy()
    })

    it('should display upload reference button', () => {
      mockUseTemplateDetail.mockReturnValue({
        data: mockTemplateDetail,
        loading: false,
        error: null,
        execute: jest.fn(),
      } as any)

      const { getByText } = render(<GenerateVideoScreen />)

      expect(getByText('generateVideo.uploadReference')).toBeTruthy()
    })

    it('should display description input field', () => {
      mockUseTemplateDetail.mockReturnValue({
        data: mockTemplateDetail,
        loading: false,
        error: null,
        execute: jest.fn(),
      } as any)

      const { getByPlaceholderText } = render(<GenerateVideoScreen />)

      expect(getByPlaceholderText('generateVideo.descriptionPlaceholder')).toBeTruthy()
    })

    it('should display generate button with correct price', () => {
      mockUseTemplateDetail.mockReturnValue({
        data: mockTemplateDetail,
        loading: false,
        error: null,
        execute: jest.fn(),
      } as any)

      const { getAllByText } = render(<GenerateVideoScreen />)

      // Price should be displayed (10 in this case)
      const priceElements = getAllByText('10')
      expect(priceElements.length).toBeGreaterThan(0)
    })
  })

  describe('Form Submission', () => {
    it('should show error when image is required but not uploaded', async () => {
      mockUseTemplateDetail.mockReturnValue({
        data: mockTemplateDetail,
        loading: false,
        error: null,
        execute: jest.fn(),
      } as any)

      const mockRunTemplate = jest.fn().mockResolvedValue({
        generationId: 'gen-123',
        error: null,
      })

      mockUseTemplateActions.mockReturnValue({
        runTemplate: mockRunTemplate,
        loading: false,
        error: null,
      } as any)

      const { getByText } = render(<GenerateVideoScreen />)

      const generateButton = getByText('generateVideo.generate')
      fireEvent.press(generateButton)

      await waitFor(() => {
        expect(Toast.show).toHaveBeenCalledWith({
          title: 'generateVideo.pleaseUploadImage',
        })
      })
    })

    it('should call runTemplate with correct parameters when form is valid', async () => {
      // Use template without image node from the start
      const templateWithoutImageNode = {
        ...mockTemplateDetail,
        formSchema: {
          startNodes: [
            {
              id: 'node_1',
              type: 'text',
            },
          ],
        },
      }

      const mockExecute = jest.fn()

      mockUseTemplateDetail.mockReturnValue({
        data: templateWithoutImageNode,
        loading: false,
        error: null,
        execute: mockExecute,
      } as any)

      const mockRunTemplate = jest.fn().mockResolvedValue({
        generationId: 'gen-123',
        error: null,
      })

      mockUseTemplateActions.mockReturnValue({
        runTemplate: mockRunTemplate,
        loading: false,
        error: null,
      } as any)

      const { getByText, getByPlaceholderText } = render(<GenerateVideoScreen />)

      // Fill description
      const descriptionInput = getByPlaceholderText('generateVideo.descriptionPlaceholder')
      fireEvent.changeText(descriptionInput, 'Test description')

      const generateButton = getByText('generateVideo.generate')
      fireEvent.press(generateButton)

      await waitFor(() => {
        expect(mockRunTemplate).toHaveBeenCalledWith({
          templateId: 'template-123',
          data: {
            node_1: 'Test description',
          },
        })
      })
    })

    it('should show loading state during generation', () => {
      mockUseTemplateDetail.mockReturnValue({
        data: {
          ...mockTemplateDetail,
          formSchema: {
            startNodes: [{ id: 'node_1', type: 'text' }],
          },
        },
        loading: false,
        error: null,
        execute: jest.fn(),
      } as any)

      mockUseTemplateActions.mockReturnValue({
        runTemplate: jest.fn(),
        loading: true,
        error: null,
      } as any)

      const { getByText } = render(<GenerateVideoScreen />)

      expect(getByText('generateVideo.generating')).toBeTruthy()
    })

    it('should handle generation errors', async () => {
      mockUseTemplateDetail.mockReturnValue({
        data: {
          ...mockTemplateDetail,
          formSchema: {
            startNodes: [{ id: 'node_1', type: 'text' }],
          },
        },
        loading: false,
        error: null,
        execute: jest.fn(),
      } as any)

      mockUseTemplateActions.mockReturnValue({
        runTemplate: jest.fn().mockResolvedValue({
          generationId: null,
          error: { message: 'Generation failed' },
        }),
        loading: false,
        error: null,
      } as any)

      const { getByText, getByPlaceholderText } = render(<GenerateVideoScreen />)

      const descriptionInput = getByPlaceholderText('generateVideo.descriptionPlaceholder')
      fireEvent.changeText(descriptionInput, 'Test description')

      const generateButton = getByText('generateVideo.generate')
      fireEvent.press(generateButton)

      await waitFor(() => {
        expect(Toast.show).toHaveBeenCalledWith({
          title: 'Generation failed',
        })
      })
    })

    it('should show notification and navigate back on successful generation', async () => {
      const mockBack = jest.fn()
      mockUseRouter.mockReturnValue({ back: mockBack } as any)

      mockUseTemplateDetail.mockReturnValue({
        data: {
          ...mockTemplateDetail,
          formSchema: {
            startNodes: [{ id: 'node_1', type: 'text' }],
          },
        },
        loading: false,
        error: null,
        execute: jest.fn(),
      } as any)

      mockUseTemplateActions.mockReturnValue({
        runTemplate: jest.fn().mockResolvedValue({
          generationId: 'gen-123',
          error: null,
        }),
        loading: false,
        error: null,
      } as any)

      const { getByText, getByPlaceholderText } = render(<GenerateVideoScreen />)

      const descriptionInput = getByPlaceholderText('generateVideo.descriptionPlaceholder')
      fireEvent.changeText(descriptionInput, 'Test description')

      const generateButton = getByText('generateVideo.generate')
      fireEvent.press(generateButton)

      await waitFor(() => {
        expect(mockBack).toHaveBeenCalled()
      }, { timeout: 4000 })
    })
  })

  describe('Image Upload', () => {
    it('should handle image upload', async () => {
      mockUseTemplateDetail.mockReturnValue({
        data: mockTemplateDetail,
        loading: false,
        error: null,
        execute: jest.fn(),
      } as any)

      const { getByText } = render(<GenerateVideoScreen />)

      const uploadButton = getByText('generateVideo.uploadReference')
      fireEvent.press(uploadButton)

      // Upload flow is handled through drawer component
      // The drawer is mocked, so we verify the button press
    })
  })

  describe('Navigation', () => {
    it('should navigate back when back button is pressed', () => {
      const mockBack = jest.fn()
      mockUseRouter.mockReturnValue({ back: mockBack } as any)

      mockUseTemplateDetail.mockReturnValue({
        data: mockTemplateDetail,
        loading: false,
        error: null,
        execute: jest.fn(),
      } as any)

      render(<GenerateVideoScreen />)

      // Component should render successfully
      // Back button navigation is tested implicitly
    })
  })

  describe('Edge Cases', () => {
    it('should handle template without formSchema', () => {
      mockUseTemplateDetail.mockReturnValue({
        data: {
          ...mockTemplateDetail,
          formSchema: undefined,
        },
        loading: false,
        error: null,
        execute: jest.fn(),
      } as any)

      const { getByText } = render(<GenerateVideoScreen />)

      expect(getByText('generateVideo.uploadReference')).toBeTruthy()
    })

    it('should handle template with empty startNodes', () => {
      mockUseTemplateDetail.mockReturnValue({
        data: {
          ...mockTemplateDetail,
          formSchema: {
            startNodes: [],
          },
        },
        loading: false,
        error: null,
        execute: jest.fn(),
      } as any)

      const { getByText } = render(<GenerateVideoScreen />)

      expect(getByText('generateVideo.uploadReference')).toBeTruthy()
    })

    it('should handle template without price', () => {
      mockUseTemplateDetail.mockReturnValue({
        data: {
          ...mockTemplateDetail,
          price: undefined,
        },
        loading: false,
        error: null,
        execute: jest.fn(),
      } as any)

      const { getAllByText } = render(<GenerateVideoScreen />)

      // Should default to 10
      const priceElements = getAllByText('10')
      expect(priceElements.length).toBeGreaterThan(0)
    })
  })
})
