import React from 'react'
import { render, screen, waitFor } from '../../../../test-utils'
import userEvent from '@testing-library/user-event'
import ClientsPage from '../page'
import { clientService } from '../../../../services/api'
import { Client } from '../../../../types/btp'

// Mock des services
jest.mock('../../../../services/api')

const mockClientService = clientService as jest.Mocked<typeof clientService>

const mockClients: Client[] = [
  {
    id: '1',
    nom: 'Dupont',
    prenom: 'Jean',
    entreprise: 'Entreprise ABC',
    email: 'jean.dupont@abc.com',
    telephone: '0612345678',
    adresse: '123 rue de la Paix',
    codePostal: '75001',
    ville: 'Paris',
    numeroTVA: 'FR12345678901',
    siret: '12345678901234',
    actif: true,
  },
  {
    id: '2',
    nom: 'Martin',
    prenom: 'Marie',
    entreprise: 'Société XYZ',
    email: 'marie.martin@xyz.com',
    telephone: '0687654321',
    adresse: '456 avenue des Champs',
    codePostal: '75008',
    ville: 'Paris',
    numeroTVA: 'FR98765432109',
    siret: '98765432109876',
    actif: true,
  },
]

describe('Page Clients', () => {
  beforeEach(() => {
    jest.clearAllMocks()
    mockClientService.getAll.mockResolvedValue(mockClients)
  })

  it('devrait charger et afficher la liste des clients', async () => {
    render(<ClientsPage />)
    
    expect(screen.getByText('Gestion des Clients')).toBeInTheDocument()
    
    await waitFor(() => {
      expect(screen.getByText('Jean Dupont')).toBeInTheDocument()
      expect(screen.getByText('Marie Martin')).toBeInTheDocument()
    })
    
    expect(mockClientService.getAll).toHaveBeenCalledTimes(1)
  })

  it('devrait permettre d\'ouvrir le formulaire de création', async () => {
    const user = userEvent.setup()
    render(<ClientsPage />)
    
    await waitFor(() => {
      expect(screen.getByText('Jean Dupont')).toBeInTheDocument()
    })
    
    const newButton = screen.getByText('Nouveau')
    await user.click(newButton)
    
    expect(screen.getByText('Détails du Client')).toBeInTheDocument()
    expect(screen.getByLabelText('Nom')).toBeInTheDocument()
    expect(screen.getByLabelText('Prénom')).toBeInTheDocument()
  })

  it('devrait permettre de créer un nouveau client', async () => {
    const user = userEvent.setup()
    const newClient = {
      id: '3',
      nom: 'Nouveau',
      prenom: 'Client',
      entreprise: 'Nouvelle Entreprise',
      email: 'nouveau@client.com',
      telephone: '0123456789',
      adresse: '789 rue Neuve',
      codePostal: '69000',
      ville: 'Lyon',
      numeroTVA: 'FR11111111111',
      siret: '11111111111111',
      actif: true,
    }
    
    mockClientService.create.mockResolvedValue(newClient)
    
    render(<ClientsPage />)
    
    await waitFor(() => {
      expect(screen.getByText('Jean Dupont')).toBeInTheDocument()
    })
    
    // Ouvrir le formulaire
    const newButton = screen.getByText('Nouveau')
    await user.click(newButton)
    
    // Remplir le formulaire
    await user.type(screen.getByLabelText('Nom'), 'Nouveau')
    await user.type(screen.getByLabelText('Prénom'), 'Client')
    await user.type(screen.getByLabelText('Entreprise'), 'Nouvelle Entreprise')
    await user.type(screen.getByLabelText('Email'), 'nouveau@client.com')
    await user.type(screen.getByLabelText('Téléphone'), '0123456789')
    await user.type(screen.getByLabelText('Adresse'), '789 rue Neuve')
    await user.type(screen.getByLabelText('Code Postal'), '69000')
    await user.type(screen.getByLabelText('Ville'), 'Lyon')
    
    // Sauvegarder
    const saveButton = screen.getByText('Sauvegarder')
    await user.click(saveButton)
    
    await waitFor(() => {
      expect(mockClientService.create).toHaveBeenCalledWith({
        id: '',
        nom: 'Nouveau',
        prenom: 'Client',
        entreprise: 'Nouvelle Entreprise',
        email: 'nouveau@client.com',
        telephone: '0123456789',
        adresse: '789 rue Neuve',
        codePostal: '69000',
        ville: 'Lyon',
        numeroTVA: '',
        siret: '',
        actif: true,
      })
    })
  })

  it('devrait permettre de modifier un client existant', async () => {
    const user = userEvent.setup()
    const updatedClient = { ...mockClients[0], nom: 'Dupont-Modifié' }
    
    mockClientService.update.mockResolvedValue(updatedClient)
    
    render(<ClientsPage />)
    
    await waitFor(() => {
      expect(screen.getByText('Jean Dupont')).toBeInTheDocument()
    })
    
    // Cliquer sur le bouton d'édition
    const editButtons = screen.getAllByRole('button', { name: '' })
    const editButton = editButtons.find(button => 
      button.querySelector('.pi-pencil')
    )
    expect(editButton).toBeInTheDocument()
    await user.click(editButton!)
    
    // Modifier le nom
    const nomInput = screen.getByLabelText('Nom')
    await user.clear(nomInput)
    await user.type(nomInput, 'Dupont-Modifié')
    
    // Sauvegarder
    const saveButton = screen.getByText('Sauvegarder')
    await user.click(saveButton)
    
    await waitFor(() => {
      expect(mockClientService.update).toHaveBeenCalledWith('1', {
        ...mockClients[0],
        nom: 'Dupont-Modifié',
      })
    })
  })

  it('devrait permettre de supprimer un client', async () => {
    const user = userEvent.setup()
    mockClientService.delete.mockResolvedValue()
    
    render(<ClientsPage />)
    
    await waitFor(() => {
      expect(screen.getByText('Jean Dupont')).toBeInTheDocument()
    })
    
    // Cliquer sur le bouton de suppression
    const deleteButtons = screen.getAllByRole('button', { name: '' })
    const deleteButton = deleteButtons.find(button => 
      button.querySelector('.pi-trash')
    )
    expect(deleteButton).toBeInTheDocument()
    await user.click(deleteButton!)
    
    // Confirmer la suppression
    expect(screen.getByText('Êtes-vous sûr de vouloir supprimer Jean Dupont ?')).toBeInTheDocument()
    const confirmButton = screen.getByText('Oui')
    await user.click(confirmButton)
    
    await waitFor(() => {
      expect(mockClientService.delete).toHaveBeenCalledWith('1')
    })
  })

  it('devrait permettre la recherche dans la liste', async () => {
    const user = userEvent.setup()
    render(<ClientsPage />)
    
    await waitFor(() => {
      expect(screen.getByText('Jean Dupont')).toBeInTheDocument()
      expect(screen.getByText('Marie Martin')).toBeInTheDocument()
    })
    
    // Rechercher "Jean"
    const searchInput = screen.getByPlaceholderText('Rechercher...')
    await user.type(searchInput, 'Jean')
    
    // La recherche est gérée par PrimeReact DataTable
    // On vérifie que l'input a bien la valeur
    expect(searchInput).toHaveValue('Jean')
  })

  it('devrait permettre d\'exporter les données', async () => {
    const user = userEvent.setup()
    render(<ClientsPage />)
    
    await waitFor(() => {
      expect(screen.getByText('Jean Dupont')).toBeInTheDocument()
    })
    
    const exportButton = screen.getByText('Exporter')
    expect(exportButton).toBeInTheDocument()
    
    // L'export est géré par PrimeReact DataTable
    await user.click(exportButton)
  })

  it('devrait valider les champs requis', async () => {
    const user = userEvent.setup()
    render(<ClientsPage />)
    
    await waitFor(() => {
      expect(screen.getByText('Jean Dupont')).toBeInTheDocument()
    })
    
    // Ouvrir le formulaire
    const newButton = screen.getByText('Nouveau')
    await user.click(newButton)
    
    // Essayer de sauvegarder sans remplir les champs requis
    const saveButton = screen.getByText('Sauvegarder')
    await user.click(saveButton)
    
    // Vérifier les messages d'erreur
    await waitFor(() => {
      expect(screen.getByText('Le nom est requis.')).toBeInTheDocument()
      expect(screen.getByText('Le prénom est requis.')).toBeInTheDocument()
    })
    
    // Le service ne devrait pas être appelé
    expect(mockClientService.create).not.toHaveBeenCalled()
  })

  it('devrait afficher les erreurs de l\'API', async () => {
    const user = userEvent.setup()
    mockClientService.create.mockRejectedValue(new Error('Erreur serveur'))
    
    render(<ClientsPage />)
    
    await waitFor(() => {
      expect(screen.getByText('Jean Dupont')).toBeInTheDocument()
    })
    
    // Ouvrir le formulaire et remplir les champs requis
    const newButton = screen.getByText('Nouveau')
    await user.click(newButton)
    
    await user.type(screen.getByLabelText('Nom'), 'Test')
    await user.type(screen.getByLabelText('Prénom'), 'Client')
    
    // Sauvegarder
    const saveButton = screen.getByText('Sauvegarder')
    await user.click(saveButton)
    
    // Vérifier qu'une erreur est affichée
    await waitFor(() => {
      expect(screen.getByText('Impossible de sauvegarder le client')).toBeInTheDocument()
    })
  })

  it('devrait permettre la suppression multiple', async () => {
    const user = userEvent.setup()
    mockClientService.delete.mockResolvedValue()
    
    render(<ClientsPage />)
    
    await waitFor(() => {
      expect(screen.getByText('Jean Dupont')).toBeInTheDocument()
    })
    
    // Sélectionner plusieurs clients
    const checkboxes = screen.getAllByRole('checkbox')
    await user.click(checkboxes[1]) // Premier client
    await user.click(checkboxes[2]) // Deuxième client
    
    // Supprimer les clients sélectionnés
    const deleteButton = screen.getByText('Supprimer')
    await user.click(deleteButton)
    
    // Confirmer la suppression
    const confirmButton = screen.getByText('Oui')
    await user.click(confirmButton)
    
    await waitFor(() => {
      expect(mockClientService.delete).toHaveBeenCalledTimes(2)
    })
  })

  it('devrait afficher les statuts des clients', async () => {
    render(<ClientsPage />)
    
    await waitFor(() => {
      expect(screen.getByText('Jean Dupont')).toBeInTheDocument()
    })
    
    // Vérifier que les statuts "Actif" sont affichés
    const activeStatuses = screen.getAllByText('Actif')
    expect(activeStatuses).toHaveLength(2)
  })

  it('devrait formater les numéros de téléphone', async () => {
    render(<ClientsPage />)
    
    await waitFor(() => {
      expect(screen.getByText('Jean Dupont')).toBeInTheDocument()
    })
    
    // Les numéros de téléphone sont formatés par la fonction formatPhoneNumber
    expect(screen.getByText('0612345678')).toBeInTheDocument()
    expect(screen.getByText('0687654321')).toBeInTheDocument()
  })

  it('devrait formater les adresses complètes', async () => {
    render(<ClientsPage />)
    
    await waitFor(() => {
      expect(screen.getByText('Jean Dupont')).toBeInTheDocument()
    })
    
    // Les adresses sont formatées par la fonction formatAddress
    expect(screen.getByText('123 rue de la Paix, 75001 Paris')).toBeInTheDocument()
    expect(screen.getByText('456 avenue des Champs, 75008 Paris')).toBeInTheDocument()
  })

  it('devrait gérer l\'état de chargement', () => {
    mockClientService.getAll.mockImplementation(
      () => new Promise(() => {}) // Promise qui ne se résout jamais
    )
    
    render(<ClientsPage />)
    
    // Vérifier que le tableau est en état de chargement
    const dataTable = document.querySelector('[data-pc-name="datatable"]')
    expect(dataTable).toBeInTheDocument()
  })

  it('devrait annuler les modifications', async () => {
    const user = userEvent.setup()
    render(<ClientsPage />)
    
    await waitFor(() => {
      expect(screen.getByText('Jean Dupont')).toBeInTheDocument()
    })
    
    // Ouvrir le formulaire
    const newButton = screen.getByText('Nouveau')
    await user.click(newButton)
    
    // Remplir partiellement le formulaire
    await user.type(screen.getByLabelText('Nom'), 'Test')
    
    // Annuler
    const cancelButton = screen.getByText('Annuler')
    await user.click(cancelButton)
    
    // Vérifier que le formulaire est fermé
    expect(screen.queryByText('Détails du Client')).not.toBeInTheDocument()
  })
})