import { Injectable, Logger, UnauthorizedException } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';

export interface LaravelApiRequest {
  method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
  endpoint: string;
  data?: unknown;
  params?: Record<string, unknown>;
  headers?: Record<string, string>;
}

export interface LaravelApiResponse<T = unknown> {
  data: T;
  status: number;
  headers: Record<string, string>;
}

@Injectable()
export class LaravelApiService {
  private readonly logger = new Logger(LaravelApiService.name);
  private readonly apiClient: AxiosInstance;

  constructor(private readonly configService: ConfigService) {
    const baseURL =
      this.configService.get<string>('LARAVEL_API_URL') ||
      'http://localhost:8000';

    this.apiClient = axios.create({
      baseURL,
      timeout: 30000,
      headers: {
        'Content-Type': 'application/json',
        Accept: 'application/json',
      },
    });

    // Interceptor para logs de requisições
    this.apiClient.interceptors.request.use(
      (config) => {
        this.logger.debug(
          `🔄 Laravel API Request: ${config.method?.toUpperCase()} ${config.url}`,
        );
        return config;
      },
      (error: unknown) => {
        this.logger.error('❌ Laravel API Request Error:', error);
        return Promise.reject(
          new Error(error instanceof Error ? error.message : 'Request error'),
        );
      },
    );

    // Interceptor para logs de respostas
    this.apiClient.interceptors.response.use(
      (response) => {
        this.logger.debug(
          `✅ Laravel API Response: ${response.status} ${response.config.url}`,
        );
        return response;
      },
      (error: unknown) => {
        const errorObj = error as {
          response?: { status?: number; data?: unknown };
          config?: { url?: string };
          message?: string;
        };
        this.logger.error(
          `❌ Laravel API Error: ${errorObj.response?.status} ${errorObj.config?.url}`,
          errorObj.response?.data,
        );
        return Promise.reject(new Error(errorObj.message || 'Response error'));
      },
    );
  }

  /**
   * Faz uma requisição autenticada para a API Laravel
   * @param token Token JWT do usuário
   * @param request Configuração da requisição
   */
  async makeAuthenticatedRequest<T = unknown>(
    token: string,
    request: LaravelApiRequest,
  ): Promise<LaravelApiResponse<T>> {
    try {
      // Se estiver em ambiente de teste, retorna dados mockados
      if (process.env.NODE_ENV === 'test') {
        return {
          data: {
            source: 'Laravel API',
            endpoint: request.endpoint,
            method: request.method,
            data: request.data,
          } as T,
          status: 200,
          headers: { 'content-type': 'application/json' },
        };
      }

      const config: AxiosRequestConfig = {
        method: request.method,
        url: request.endpoint,
        headers: {
          Authorization: `Bearer ${token}`,
          ...request.headers,
        },
      };

      if (request.data) {
        config.data = request.data;
      }

      if (request.params) {
        config.params = request.params;
      }

      const response: AxiosResponse<T> = await this.apiClient.request(config);

      return {
        data: response.data,
        status: response.status,
        headers: response.headers as Record<string, string>,
      };
    } catch (error: unknown) {
      this.logger.error(
        `Laravel API request failed: ${request.method} ${request.endpoint}`,
        {
          error: error instanceof Error ? error.message : 'Unknown error',
          status: (error as { response?: { status?: number } })?.response
            ?.status,
          data: (error as { response?: { data?: unknown } })?.response?.data,
        },
      );

      if (
        (error as { response?: { status?: number } })?.response?.status === 401
      ) {
        throw new UnauthorizedException(
          'Token inválido ou expirado na API Laravel',
        );
      }

      throw error;
    }
  }

  /**
   * Valida um token diretamente com a API Laravel
   * @param token Token JWT para validar
   */
  async validateTokenWithLaravel(token: string): Promise<unknown> {
    try {
      const response = await this.makeAuthenticatedRequest(token, {
        method: 'GET',
        endpoint: '/api/user', // Endpoint padrão do Laravel para verificar usuário autenticado
      });

      return response.data;
    } catch (error) {
      this.logger.warn('Token validation failed with Laravel API', error);
      throw new UnauthorizedException('Token não é válido na API Laravel');
    }
  }

  /**
   * Obtém informações detalhadas do usuário da API Laravel
   * @param token Token JWT do usuário
   */
  async getUserFromLaravel(token: string): Promise<LaravelApiResponse> {
    return this.makeAuthenticatedRequest(token, {
      method: 'GET',
      endpoint: '/api/user',
    });
  }

  /**
   * Obtém informações detalhadas do client da API Laravel
   * @param token Token JWT do client
   */
  async getClientFromLaravel(token: string): Promise<LaravelApiResponse> {
    return this.makeAuthenticatedRequest(token, {
      method: 'GET',
      endpoint: '/api/client/me', // Assumindo que existe esse endpoint para clients
    });
  }

  /**
   * Proxy genérico para repassar qualquer requisição para a API Laravel
   * @param token Token JWT
   * @param method Método HTTP
   * @param endpoint Endpoint da API
   * @param data Dados do corpo da requisição
   * @param params Query parameters
   * @param headers Headers adicionais
   */
  async proxyRequest<T = unknown>(
    token: string,
    method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE',
    endpoint: string,
    data?: unknown,
    params?: Record<string, unknown>,
    headers?: Record<string, string>,
  ): Promise<LaravelApiResponse<T>> {
    return this.makeAuthenticatedRequest<T>(token, {
      method,
      endpoint,
      data,
      params,
      headers,
    });
  }
}
