import { describe, it, expect, beforeEach, vi } from 'vitest'
import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import OnboardingForm from '../OnboardingForm'
import { onboardingService } from '../../services/onboarding.service'
import type { OnboardingResponse } from '../../types/onboarding'

// Mock the onboarding service
vi.mock('../../services/onboarding.service', () => ({
  onboardingService: {
    onboardEmployee: vi.fn(),
  },
}))

// Mock Next.js navigation
vi.mock('next/navigation', () => ({
  useRouter: () => ({
    push: vi.fn(),
    refresh: vi.fn(),
  }),
}))

describe('OnboardingForm', () => {
  beforeEach(() => {
    vi.clearAllMocks()
  })

  describe('Rendering', () => {
    it('should render all required fields', () => {
      render(<OnboardingForm />)

      // 必填欄位
      expect(screen.getByLabelText(/Resume ID/i)).toBeInTheDocument()
      expect(screen.getByLabelText(/Keycloak User ID/i)).toBeInTheDocument()
      expect(screen.getByLabelText(/Keycloak Username/i)).toBeInTheDocument()
      expect(screen.getByLabelText(/Hire Date/i)).toBeInTheDocument()

      // 選填欄位
      expect(screen.getByLabelText(/Storage Quota \(GB\)/i)).toBeInTheDocument()
      expect(screen.getByLabelText(/Email Quota \(MB\)/i)).toBeInTheDocument()

      // 提交按鈕
      expect(screen.getByRole('button', { name: /Submit/i })).toBeInTheDocument()
    })

    it('should render department assignment section', () => {
      render(<OnboardingForm />)

      expect(screen.getByText(/Department Assignments/i)).toBeInTheDocument()
      expect(screen.getByRole('button', { name: /Add Department/i })).toBeInTheDocument()
    })

    it('should render role assignment section', () => {
      render(<OnboardingForm />)

      expect(screen.getByText(/Role Assignments/i)).toBeInTheDocument()
    })
  })

  describe('Form Validation', () => {
    it('should show validation errors for required fields', async () => {
      const user = userEvent.setup()
      render(<OnboardingForm />)

      const submitButton = screen.getByRole('button', { name: /Submit/i })
      await user.click(submitButton)

      await waitFor(() => {
        expect(screen.getByText(/Resume ID is required/i)).toBeInTheDocument()
        expect(screen.getByText(/Keycloak User ID is required/i)).toBeInTheDocument()
        expect(screen.getByText(/Keycloak Username is required/i)).toBeInTheDocument()
        expect(screen.getByText(/Hire Date is required/i)).toBeInTheDocument()
      })
    })

    it('should validate Keycloak User ID format (UUID)', async () => {
      const user = userEvent.setup()
      render(<OnboardingForm />)

      const keycloakUserIdInput = screen.getByLabelText(/Keycloak User ID/i)
      await user.type(keycloakUserIdInput, 'invalid-uuid')

      const submitButton = screen.getByRole('button', { name: /Submit/i })
      await user.click(submitButton)

      await waitFor(() => {
        expect(screen.getByText(/Invalid UUID format/i)).toBeInTheDocument()
      })
    })

    it('should validate storage quota is a positive number', async () => {
      const user = userEvent.setup()
      render(<OnboardingForm />)

      const storageQuotaInput = screen.getByLabelText(/Storage Quota \(GB\)/i)
      await user.clear(storageQuotaInput)
      await user.type(storageQuotaInput, '-10')

      const submitButton = screen.getByRole('button', { name: /Submit/i })
      await user.click(submitButton)

      await waitFor(() => {
        expect(screen.getByText(/Storage quota must be positive/i)).toBeInTheDocument()
      })
    })
  })

  describe('Department Assignment', () => {
    it('should add a new department assignment', async () => {
      const user = userEvent.setup()
      render(<OnboardingForm />)

      const addButton = screen.getByRole('button', { name: /Add Department/i })
      await user.click(addButton)

      await waitFor(() => {
        expect(screen.getByLabelText(/Department ID/i)).toBeInTheDocument()
        expect(screen.getByLabelText(/Position/i)).toBeInTheDocument()
        expect(screen.getByLabelText(/Membership Type/i)).toBeInTheDocument()
      })
    })

    it('should remove a department assignment', async () => {
      const user = userEvent.setup()
      render(<OnboardingForm />)

      // 添加部門
      const addButton = screen.getByRole('button', { name: /Add Department/i })
      await user.click(addButton)

      // 刪除部門
      const removeButton = screen.getByRole('button', { name: /Remove/i })
      await user.click(removeButton)

      await waitFor(() => {
        expect(screen.queryByLabelText(/Department ID/i)).not.toBeInTheDocument()
      })
    })

    it('should validate department assignment fields', async () => {
      const user = userEvent.setup()
      render(<OnboardingForm />)

      const addButton = screen.getByRole('button', { name: /Add Department/i })
      await user.click(addButton)

      const submitButton = screen.getByRole('button', { name: /Submit/i })
      await user.click(submitButton)

      await waitFor(() => {
        expect(screen.getByText(/Department ID is required/i)).toBeInTheDocument()
        expect(screen.getByText(/Position is required/i)).toBeInTheDocument()
      })
    })
  })

  describe('Form Submission', () => {
    it('should submit form successfully with valid data', async () => {
      const user = userEvent.setup()
      const mockResponse: OnboardingResponse = {
        message: 'Employee onboarded successfully',
        employee: {
          tenant_id: 1,
          seq_no: 1,
          tenant_emp_code: 'PWD0001',
          keycloak_user_id: '550e8400-e29b-41d4-a716-446655440000',
          keycloak_username: 'wang.ming',
          name: '王明',
          hire_date: '2026-02-21',
        },
        summary: {
          departments_assigned: 1,
          roles_assigned: 2,
          services_enabled: 5,
        },
      }

      vi.mocked(onboardingService.onboardEmployee).mockResolvedValueOnce(mockResponse)

      render(<OnboardingForm />)

      // 填寫表單
      await user.type(screen.getByLabelText(/Resume ID/i), '1')
      await user.type(
        screen.getByLabelText(/Keycloak User ID/i),
        '550e8400-e29b-41d4-a716-446655440000'
      )
      await user.type(screen.getByLabelText(/Keycloak Username/i), 'wang.ming')
      await user.type(screen.getByLabelText(/Hire Date/i), '2026-02-21')

      // 提交表單
      const submitButton = screen.getByRole('button', { name: /Submit/i })
      await user.click(submitButton)

      await waitFor(() => {
        expect(onboardingService.onboardEmployee).toHaveBeenCalledWith(
          expect.objectContaining({
            resume_id: 1,
            keycloak_user_id: '550e8400-e29b-41d4-a716-446655440000',
            keycloak_username: 'wang.ming',
            hire_date: '2026-02-21',
          })
        )
      })

      // 驗證成功訊息
      await waitFor(() => {
        expect(screen.getByText(/Employee onboarded successfully/i)).toBeInTheDocument()
      })
    })

    it('should handle API errors gracefully', async () => {
      const user = userEvent.setup()
      const errorMessage = 'Resume ID not found'

      vi.mocked(onboardingService.onboardEmployee).mockRejectedValueOnce({
        response: {
          data: { detail: errorMessage },
          status: 404,
        },
      })

      render(<OnboardingForm />)

      // 填寫表單
      await user.type(screen.getByLabelText(/Resume ID/i), '999')
      await user.type(
        screen.getByLabelText(/Keycloak User ID/i),
        '550e8400-e29b-41d4-a716-446655440000'
      )
      await user.type(screen.getByLabelText(/Keycloak Username/i), 'test.user')
      await user.type(screen.getByLabelText(/Hire Date/i), '2026-02-21')

      // 提交表單
      const submitButton = screen.getByRole('button', { name: /Submit/i })
      await user.click(submitButton)

      await waitFor(() => {
        expect(screen.getByText(errorMessage)).toBeInTheDocument()
      })
    })

    it('should show loading state during submission', async () => {
      const user = userEvent.setup()

      // 模擬延遲的 API 回應
      vi.mocked(onboardingService.onboardEmployee).mockImplementation(
        () => new Promise((resolve) => setTimeout(resolve, 100))
      )

      render(<OnboardingForm />)

      // 填寫表單
      await user.type(screen.getByLabelText(/Resume ID/i), '1')
      await user.type(
        screen.getByLabelText(/Keycloak User ID/i),
        '550e8400-e29b-41d4-a716-446655440000'
      )
      await user.type(screen.getByLabelText(/Keycloak Username/i), 'wang.ming')
      await user.type(screen.getByLabelText(/Hire Date/i), '2026-02-21')

      // 提交表單
      const submitButton = screen.getByRole('button', { name: /Submit/i })
      await user.click(submitButton)

      // 驗證載入狀態
      expect(screen.getByText(/Submitting.../i)).toBeInTheDocument()
      expect(submitButton).toBeDisabled()
    })

    it('should reset form after successful submission', async () => {
      const user = userEvent.setup()
      const mockResponse: OnboardingResponse = {
        message: 'Employee onboarded successfully',
        employee: {
          tenant_id: 1,
          seq_no: 1,
          tenant_emp_code: 'PWD0001',
          keycloak_user_id: '550e8400-e29b-41d4-a716-446655440000',
          keycloak_username: 'wang.ming',
          name: '王明',
          hire_date: '2026-02-21',
        },
        summary: {
          departments_assigned: 0,
          roles_assigned: 0,
          services_enabled: 5,
        },
      }

      vi.mocked(onboardingService.onboardEmployee).mockResolvedValueOnce(mockResponse)

      render(<OnboardingForm />)

      // 填寫表單
      const resumeIdInput = screen.getByLabelText(/Resume ID/i) as HTMLInputElement
      await user.type(resumeIdInput, '1')
      await user.type(
        screen.getByLabelText(/Keycloak User ID/i),
        '550e8400-e29b-41d4-a716-446655440000'
      )
      await user.type(screen.getByLabelText(/Keycloak Username/i), 'wang.ming')
      await user.type(screen.getByLabelText(/Hire Date/i), '2026-02-21')

      // 提交表單
      const submitButton = screen.getByRole('button', { name: /Submit/i })
      await user.click(submitButton)

      await waitFor(() => {
        expect(screen.getByText(/Employee onboarded successfully/i)).toBeInTheDocument()
      })

      // 驗證表單已重置
      await waitFor(() => {
        expect(resumeIdInput.value).toBe('')
      })
    })
  })
})
