import { describe, it, expect, beforeEach, vi } from 'vitest'
import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { tenantService } from '../../services/tenant.service'
import TenantCreateForm from '../TenantCreateForm'

// Mock tenant service
vi.mock('../../services/tenant.service', () => ({
  tenantService: {
    createTenant: vi.fn(),
  },
}))

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

  describe('Form Rendering', () => {
    it('should render all required form fields', () => {
      // Act
      render(<TenantCreateForm onSuccess={vi.fn()} onCancel={vi.fn()} />)

      // Assert - Basic Info Section
      expect(screen.getByLabelText(/^tenant code/i)).toBeInTheDocument()
      expect(screen.getByLabelText(/^company name \*$/i)).toBeInTheDocument()
      expect(screen.getByLabelText(/company name \(english\)/i)).toBeInTheDocument()
      expect(screen.getByLabelText(/^tax id$/i)).toBeInTheDocument()
      expect(screen.getByLabelText(/employee prefix/i)).toBeInTheDocument()

      // Assert - Contact Info Section
      expect(screen.getByLabelText(/phone/i)).toBeInTheDocument()
      expect(screen.getByLabelText(/address/i)).toBeInTheDocument()
      expect(screen.getByLabelText(/website/i)).toBeInTheDocument()

      // Assert - Plan Settings Section
      expect(screen.getByLabelText(/plan id/i)).toBeInTheDocument()
      expect(screen.getByLabelText(/max users/i)).toBeInTheDocument()
      expect(screen.getByLabelText(/storage quota/i)).toBeInTheDocument()

      // Assert - Admin Account Section
      expect(screen.getByLabelText(/admin username/i)).toBeInTheDocument()
      expect(screen.getByLabelText(/admin email/i)).toBeInTheDocument()
      expect(screen.getByLabelText(/admin name/i)).toBeInTheDocument()
      expect(screen.getByLabelText(/admin password/i)).toBeInTheDocument()

      // Assert - Buttons
      expect(screen.getByRole('button', { name: /create tenant/i })).toBeInTheDocument()
      expect(screen.getByRole('button', { name: /cancel/i })).toBeInTheDocument()
    })

    it('should have default values for plan settings', () => {
      // Act
      render(<TenantCreateForm onSuccess={vi.fn()} />)

      // Assert
      const planIdInput = screen.getByLabelText(/plan id/i) as HTMLInputElement
      const maxUsersInput = screen.getByLabelText(/max users/i) as HTMLInputElement
      const storageQuotaInput = screen.getByLabelText(/storage quota/i) as HTMLInputElement

      expect(planIdInput.value).toBe('starter')
      expect(maxUsersInput.value).toBe('5')
      expect(storageQuotaInput.value).toBe('100')
    })
  })

  describe('Form Validation', () => {
    it('should show error when tenant code is empty', async () => {
      // Arrange
      const user = userEvent.setup()
      render(<TenantCreateForm onSuccess={vi.fn()} />)

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

      // Assert
      await waitFor(() => {
        expect(screen.getByText(/tenant code is required/i)).toBeInTheDocument()
      })
    })

    it('should show error when company name is empty', async () => {
      // Arrange
      const user = userEvent.setup()
      render(<TenantCreateForm onSuccess={vi.fn()} />)

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

      // Assert
      await waitFor(() => {
        expect(screen.getByText(/company name is required/i)).toBeInTheDocument()
      })
    })

    it('should validate tax id format (8 digits)', async () => {
      // Arrange
      const user = userEvent.setup()
      render(<TenantCreateForm onSuccess={vi.fn()} />)

      // Act
      const taxIdInput = screen.getByLabelText(/tax id/i)
      await user.type(taxIdInput, '123') // Invalid: less than 8 digits

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

      // Assert
      await waitFor(() => {
        expect(screen.getByText(/tax id must be 8 digits/i)).toBeInTheDocument()
      })
    })

    it.skip('should validate email format', async () => {
      // Arrange
      const user = userEvent.setup()
      render(<TenantCreateForm onSuccess={vi.fn()} />)

      // Act - Fill required fields first
      await user.type(screen.getByLabelText(/^tenant code/i), 'TEST')
      await user.type(screen.getByLabelText(/^company name \*$/i), '測試公司')
      await user.type(screen.getByLabelText(/employee prefix/i), 'T')
      await user.type(screen.getByLabelText(/admin username/i), 'admin')
      await user.type(screen.getByLabelText(/admin email/i), 'invalidemail') // Missing @
      await user.type(screen.getByLabelText(/admin name/i), 'Admin User')
      await user.type(screen.getByLabelText(/admin password/i), 'TempPass123!')

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

      // Assert
      await waitFor(() => {
        const errorElement = screen.queryByText(/invalid email format/i)
        expect(errorElement).toBeInTheDocument()
      }, { timeout: 3000 })
    })

    it('should validate password length (minimum 8 characters)', async () => {
      // Arrange
      const user = userEvent.setup()
      render(<TenantCreateForm onSuccess={vi.fn()} />)

      // Act
      const passwordInput = screen.getByLabelText(/admin password/i)
      await user.type(passwordInput, '12345') // Less than 8 characters

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

      // Assert
      await waitFor(() => {
        expect(screen.getByText(/password must be at least 8 characters/i)).toBeInTheDocument()
      })
    })

    it('should validate employee prefix is required', async () => {
      // Arrange
      const user = userEvent.setup()
      render(<TenantCreateForm onSuccess={vi.fn()} />)

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

      // Assert
      await waitFor(() => {
        expect(screen.getByText(/employee prefix is required/i)).toBeInTheDocument()
      })
    })
  })

  describe('Form Submission', () => {
    it('should submit form with valid data', async () => {
      // Arrange
      const user = userEvent.setup()
      const onSuccess = vi.fn()
      const mockResponse = {
        message: 'Tenant created successfully',
        tenant: {
          id: 1,
          code: 'TEST',
          name: '測試公司',
          keycloak_realm: 'porscheworld-test',
        },
        admin_user: {
          id: 1,
          username: 'admin',
          email: 'admin@test.com',
        },
        keycloak_realm: 'porscheworld-test',
        temporary_password: 'TempPass123!',
      }

      vi.mocked(tenantService.createTenant).mockResolvedValueOnce(mockResponse)

      render(<TenantCreateForm onSuccess={onSuccess} />)

      // Act - Fill in form
      await user.type(screen.getByLabelText(/tenant code/i), 'TEST')
      await user.type(screen.getByLabelText(/^company name \*$/i), '測試公司')
      await user.type(screen.getByLabelText(/tax id/i), '12345678')
      await user.type(screen.getByLabelText(/employee prefix/i), 'T')
      await user.type(screen.getByLabelText(/admin username/i), 'admin')
      await user.type(screen.getByLabelText(/admin email/i), 'admin@test.com')
      await user.type(screen.getByLabelText(/admin name/i), 'Admin User')
      await user.type(screen.getByLabelText(/admin password/i), 'TempPass123!')

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

      // Assert
      await waitFor(() => {
        expect(tenantService.createTenant).toHaveBeenCalledWith({
          code: 'TEST',
          name: '測試公司',
          name_eng: '',
          tax_id: '12345678',
          prefix: 'T',
          tel: '',
          add: '',
          url: '',
          plan_id: 'starter',
          max_users: 5,
          storage_quota_gb: 100,
          admin_username: 'admin',
          admin_email: 'admin@test.com',
          admin_name: 'Admin User',
          admin_temp_password: 'TempPass123!',
        })
        expect(onSuccess).toHaveBeenCalledWith(mockResponse)
      })
    })

    it('should handle API error gracefully', async () => {
      // Arrange
      const user = userEvent.setup()
      vi.mocked(tenantService.createTenant).mockRejectedValueOnce({
        response: {
          data: {
            detail: "Tenant code 'TEST' already exists",
          },
        },
      })

      render(<TenantCreateForm onSuccess={vi.fn()} />)

      // Act - Fill in minimum required fields
      await user.type(screen.getByLabelText(/tenant code/i), 'TEST')
      await user.type(screen.getByLabelText(/^company name \*$/i), '測試公司')
      await user.type(screen.getByLabelText(/employee prefix/i), 'T')
      await user.type(screen.getByLabelText(/admin username/i), 'admin')
      await user.type(screen.getByLabelText(/admin email/i), 'admin@test.com')
      await user.type(screen.getByLabelText(/admin name/i), 'Admin User')
      await user.type(screen.getByLabelText(/admin password/i), 'TempPass123!')

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

      // Assert
      await waitFor(() => {
        expect(screen.getByText(/tenant code 'TEST' already exists/i)).toBeInTheDocument()
      })
    })

    it('should show loading state during submission', async () => {
      // Arrange
      const user = userEvent.setup()
      vi.mocked(tenantService.createTenant).mockImplementation(
        () => new Promise((resolve) => setTimeout(resolve, 100))
      )

      render(<TenantCreateForm onSuccess={vi.fn()} />)

      // Act - Fill in minimum required fields
      await user.type(screen.getByLabelText(/tenant code/i), 'TEST')
      await user.type(screen.getByLabelText(/^company name \*$/i), '測試公司')
      await user.type(screen.getByLabelText(/employee prefix/i), 'T')
      await user.type(screen.getByLabelText(/admin username/i), 'admin')
      await user.type(screen.getByLabelText(/admin email/i), 'admin@test.com')
      await user.type(screen.getByLabelText(/admin name/i), 'Admin User')
      await user.type(screen.getByLabelText(/admin password/i), 'TempPass123!')

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

      // Assert
      expect(screen.getByText(/creating/i)).toBeInTheDocument()
      expect(submitButton).toBeDisabled()
    })

    it('should reset form after successful submission', async () => {
      // Arrange
      const user = userEvent.setup()
      const mockResponse = {
        message: 'Tenant created successfully',
        tenant: { id: 1, code: 'TEST', name: '測試公司' },
        admin_user: { id: 1, username: 'admin' },
        keycloak_realm: 'porscheworld-test',
        temporary_password: 'TempPass123!',
      }

      vi.mocked(tenantService.createTenant).mockResolvedValueOnce(mockResponse)

      render(<TenantCreateForm onSuccess={vi.fn()} />)

      // Act - Fill and submit form
      await user.type(screen.getByLabelText(/tenant code/i), 'TEST')
      await user.type(screen.getByLabelText(/^company name \*$/i), '測試公司')
      await user.type(screen.getByLabelText(/employee prefix/i), 'T')
      await user.type(screen.getByLabelText(/admin username/i), 'admin')
      await user.type(screen.getByLabelText(/admin email/i), 'admin@test.com')
      await user.type(screen.getByLabelText(/admin name/i), 'Admin User')
      await user.type(screen.getByLabelText(/admin password/i), 'TempPass123!')

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

      // Assert - Form should be reset
      await waitFor(() => {
        const codeInput = screen.getByLabelText(/tenant code/i) as HTMLInputElement
        const nameInput = screen.getByLabelText(/^company name \*$/i) as HTMLInputElement
        expect(codeInput.value).toBe('')
        expect(nameInput.value).toBe('')
      })
    })
  })

  describe('Cancel Functionality', () => {
    it('should call onCancel when cancel button is clicked', async () => {
      // Arrange
      const user = userEvent.setup()
      const onCancel = vi.fn()
      render(<TenantCreateForm onSuccess={vi.fn()} onCancel={onCancel} />)

      // Act
      const cancelButton = screen.getByRole('button', { name: /cancel/i })
      await user.click(cancelButton)

      // Assert
      expect(onCancel).toHaveBeenCalledTimes(1)
    })
  })
})
