import { Injectable } from '@angular/core';
import { Observable, map } from 'rxjs';
import { ApiClientService } from './api/api-client.service';
import { Person } from '../interfaces/person.interface';
import { PaginatedResponse } from '../interfaces/paginate.interface';
import { DomainService } from '../components/base-domain/base-domain.component';

/**
 * 🎯 PersonService - Serviço para gestão de pessoas
 * 
 * ✨ Funcionalidades:
 * - 🔍 Busca de pessoas para remote-select
 * - 📋 CRUD completo de pessoas
 * - 🎯 Implementa DomainService<Person> para compatibilidade
 * - 🔄 Integração com API backend /api/v1/person
 * 
 * 🚀 Usado principalmente para seleção de proprietários de veículos
 */
@Injectable({
  providedIn: 'root' 
})
export class PersonService implements DomainService<Person> { 
  constructor(
    private apiClient: ApiClientService
  ) {}

  // ========================================
  // 🎯 MÉTODOS ESPECÍFICOS DO DOMÍNIO
  // ========================================

  /**
   * Busca pessoas com paginação e filtros
   */
  getPeople( 
    page = 1, 
    limit = 10, 
    filters?: {[key: string]: string}
  ): Observable<PaginatedResponse<Person>> {
    
    let url = `person?page=${page}&limit=${limit}`;
    
    if (filters) {
      const params = new URLSearchParams();
      
      for (const [key, value] of Object.entries(filters)) {
        if (value) {
          params.append(key, value);
        }
      }
      
      url += `&${params.toString()}`;
    }
    
    return this.apiClient.get<PaginatedResponse<Person>>(url);
  }

  /**
   * Busca uma pessoa específica por ID
   */
  getById(id: string | number): Observable<{ data: Person }> {
    return this.apiClient.get<{ data: Person }>(`person/${id}`);
  }

  /**
   * Remove uma pessoa
   */
  delete(id: string | number): Observable<void> {
    return this.apiClient.delete<void>(`person/${id}`);
  }

  /**
   * 🔍 Busca pessoa por CPF - usado para reaproveitar dados no cadastro de motoristas
   * @param cpf CPF da pessoa (pode incluir formatação)
   * @returns Observable com dados da pessoa se encontrada
   */
  searchByCpf(cpf: string): Observable<PaginatedResponse<Person>> {
    // Remove formatação do CPF para busca
    const cleanCpf = cpf.replace(/\D/g, '');
    return this.apiClient.get<PaginatedResponse<Person>>(`person?cpf=${cleanCpf}`);
  }

  /**
   * 🔍 Busca pessoa por CNPJ - usado para reaproveitar dados no cadastro de motoristas
   * @param cnpj CNPJ da pessoa (pode incluir formatação)
   * @returns Observable com dados da pessoa se encontrada
   */
  searchByCnpj(cnpj: string): Observable<PaginatedResponse<Person>> {
    // Remove formatação do CNPJ para busca
    const cleanCnpj = cnpj.replace(/\D/g, '');
    return this.apiClient.get<PaginatedResponse<Person>>(`person?cnpj=${cleanCnpj}`);
  }

  /**
   * 🔍 Busca pessoa por documento (CPF ou CNPJ) - método genérico
   * @param document CPF ou CNPJ da pessoa (pode incluir formatação)
   * @param documentType Tipo do documento: 'cpf' ou 'cnpj'
   * @returns Observable com dados da pessoa se encontrada
   */
  searchByDocument(document: string, documentType: 'cpf' | 'cnpj'): Observable<PaginatedResponse<Person>> {
    const cleanDocument = document.replace(/\D/g, '');
    return this.apiClient.get<PaginatedResponse<Person>>(`person?${documentType}=${cleanDocument}`);
  }

  // ========================================
  // 🎯 MÉTODOS ESPERADOS PELO BaseDomainComponent
  // ========================================

  /**
   * ✅ Método genérico para listar - chamado automaticamente pelo BaseDomainComponent
   * e usado pelo RemoteSelectComponent
   */
  getEntities(page: number, pageSize: number, filters: any): Observable<{
    data: Person[];
    totalCount: number;
    pageCount: number;
    currentPage: number;
  }> {
    return this.getPeople(page, pageSize, filters).pipe(
      map(response => ({
        data: response.data,
        totalCount: response.totalCount,
        pageCount: response.pageCount,
        currentPage: response.currentPage
      }))
    );
  }

  /**
   * ✅ Método genérico para criar - chamado automaticamente pelo BaseDomainComponent
   */
  create(data: any): Observable<Person> {
    return this.apiClient.post<Person>('person', data);
  }

  /**
   * ✅ Método genérico para atualizar - chamado automaticamente pelo BaseDomainComponent
   */
  update(id: any, data: any): Observable<Person> {
    return this.apiClient.patch<Person>(`person/${id}`, data);
  }
} 