/**
 * Cliente HTTP usando Axios
 * Chamadas diretas ao Supabase
 */

import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
import { API_CONFIG } from "./config";

class ApiClient {
  private client: AxiosInstance;

  constructor() {
    this.client = axios.create({
      baseURL: API_CONFIG.REST_URL,
      timeout: API_CONFIG.TIMEOUT,
      headers: {
        "Content-Type": "application/json",
        apikey: API_CONFIG.SUPABASE_ANON_KEY,
      },
    });

    this.setupInterceptors();
  }

  private setupInterceptors() {
    // Request interceptor - adiciona token automaticamente
    this.client.interceptors.request.use(
      (config) => {
        // Não adicionar token se a flag _skipAuth estiver presente
        if ((config as any)._skipAuth) {
          delete (config as any)._skipAuth;
          return config;
        }

        const token = localStorage.getItem(
          API_CONFIG.STORAGE_KEYS.ACCESS_TOKEN
        );

        if (token && config.headers) {
          config.headers.Authorization = `Bearer ${token}`;
          console.log(
            `[ApiClient] Request: ${config.method?.toUpperCase()} ${
              config.url
            } - Token presente: ${token.substring(0, 20)}...`
          );
        } else {
          console.warn(
            `[ApiClient] Request: ${config.method?.toUpperCase()} ${
              config.url
            } - SEM TOKEN!`
          );
        }

        return config;
      },
      (error) => {
        return Promise.reject(error);
      }
    );

    // Response interceptor - trata erros globalmente
    this.client.interceptors.response.use(
      (response) => response,
      async (error) => {
        const originalRequest = error.config;

        console.error(`[ApiClient] Erro na requisição:`, {
          url: originalRequest?.url,
          status: error.response?.status,
          message: error.message,
        });

        // Se retornar 401 e não for uma requisição de refresh/login
        if (
          error.response?.status === 401 &&
          !originalRequest._retry &&
          !originalRequest.url?.includes("auth-refresh") &&
          !originalRequest.url?.includes("auth-login")
        ) {
          originalRequest._retry = true;

          console.log("[ApiClient] Recebeu 401, tentando renovar token...");

          try {
            // Tenta renovar o token
            const refreshToken = localStorage.getItem(
              API_CONFIG.STORAGE_KEYS.REFRESH_TOKEN
            );

            if (refreshToken) {
              console.log("[ApiClient] Refresh token encontrado, renovando...");

              // Chama Supabase diretamente para renovar token
              const response = await axios.post(
                `${API_CONFIG.AUTH_URL}/token?grant_type=refresh_token`,
                {
                  refresh_token: refreshToken,
                },
                {
                  headers: {
                    "Content-Type": "application/json",
                    apikey: API_CONFIG.SUPABASE_ANON_KEY,
                  },
                }
              );

              const {
                access_token,
                refresh_token: newRefreshToken,
                user,
              } = response.data;

              console.log("[ApiClient] Token renovado com sucesso!");

              // Atualiza tokens
              localStorage.setItem(
                API_CONFIG.STORAGE_KEYS.ACCESS_TOKEN,
                access_token
              );
              localStorage.setItem(
                API_CONFIG.STORAGE_KEYS.REFRESH_TOKEN,
                newRefreshToken
              );
              localStorage.setItem(
                API_CONFIG.STORAGE_KEYS.USER,
                JSON.stringify(user)
              );

              // Atualiza o header da requisição original
              originalRequest.headers.Authorization = `Bearer ${access_token}`;

              // Refaz a requisição original
              return this.client(originalRequest);
            } else {
              console.warn("[ApiClient] Nenhum refresh token disponível!");
            }
          } catch (refreshError) {
            console.error(
              "[ApiClient] Falha ao renovar token, fazendo logout...",
              refreshError
            );
            // Se refresh falhar, limpa tudo e redireciona para home
            localStorage.removeItem(API_CONFIG.STORAGE_KEYS.ACCESS_TOKEN);
            localStorage.removeItem(API_CONFIG.STORAGE_KEYS.REFRESH_TOKEN);
            localStorage.removeItem(API_CONFIG.STORAGE_KEYS.USER);

            // Redireciona para home ao invés de login específico
            if (
              !window.location.pathname.includes("/login") &&
              window.location.pathname !== "/"
            ) {
              window.location.href = "/";
            }

            return Promise.reject(refreshError);
          }
        }

        // Se não conseguir renovar, apenas loga o erro mas NÃO limpa a sessão
        // Deixa o componente decidir o que fazer
        if (error.response?.status === 401) {
          console.error(
            "[ApiClient] 401 não tratado - requisição:",
            originalRequest?.url
          );
        }

        return Promise.reject(error);
      }
    );
  }

  // Métodos HTTP
  async get<T>(
    url: string,
    config?: AxiosRequestConfig
  ): Promise<AxiosResponse<T>> {
    const fullUrl = `${this.client.defaults.baseURL}${url}`;
    const queryString = new URLSearchParams(config?.params).toString();
    console.log(
      "[ApiClient] 🔍 GET Request COMPLETO:",
      fullUrl + (queryString ? `?${queryString}` : "")
    );
    console.log(
      "[ApiClient] GET Request:",
      url,
      "Params:",
      JSON.stringify(config?.params)
    );

    const response = await this.client.get<T>(url, config);

    console.log("[ApiClient] GET Response:", {
      status: response.status,
      dataType: typeof response.data,
      isArray: Array.isArray(response.data),
      dataLength: Array.isArray(response.data)
        ? response.data.length
        : "not array",
    });
    console.log(
      "[ApiClient] Response Data:",
      JSON.stringify(response.data, null, 2)
    );

    return response;
  }

  async post<T>(
    url: string,
    data?: unknown,
    config?: AxiosRequestConfig
  ): Promise<AxiosResponse<T>> {
    console.log("[ApiClient] POST Request:", {
      url,
      fullUrl: `${this.client.defaults.baseURL}${url}`,
      data,
      config,
    });

    try {
      const response = await this.client.post<T>(url, data, config);
      console.log("[ApiClient] POST Response:", {
        status: response.status,
        data: response.data,
      });
      return response;
    } catch (error: any) {
      console.error("[ApiClient] POST Error:", {
        url,
        fullUrl: `${this.client.defaults.baseURL}${url}`,
        status: error?.response?.status,
        statusText: error?.response?.statusText,
        data: error?.response?.data,
        message: error?.message,
      });
      throw error;
    }
  }

  /**
   * POST público - não envia token de autenticação
   * Usado para endpoints de auto-registro
   */
  async postPublic<T>(
    url: string,
    data?: unknown,
    config?: AxiosRequestConfig
  ): Promise<AxiosResponse<T>> {
    const configWithoutAuth = {
      ...config,
      headers: {
        ...config?.headers,
        // Remove Authorization header
      },
      // Flag especial para o interceptor saber que não deve adicionar token
      _skipAuth: true,
    };
    return this.client.post<T>(url, data, configWithoutAuth);
  }

  async patch<T>(
    url: string,
    data?: unknown,
    config?: AxiosRequestConfig
  ): Promise<AxiosResponse<T>> {
    console.log("[ApiClient] PATCH Request:", {
      url,
      data,
      config,
    });

    try {
      // Adicionar header Prefer para Supabase retornar os dados atualizados
      const configWithPrefer = {
        ...config,
        headers: {
          ...config?.headers,
          Prefer: "return=representation",
        },
      };

      const response = await this.client.patch<T>(url, data, configWithPrefer);
      console.log("[ApiClient] PATCH Response:", {
        status: response.status,
        data: response.data,
      });
      return response;
    } catch (error: any) {
      console.error("[ApiClient] PATCH Error:", {
        url,
        status: error?.response?.status,
        statusText: error?.response?.statusText,
        data: error?.response?.data,
        message: error?.message,
      });
      throw error;
    }
  }

  async delete<T>(
    url: string,
    config?: AxiosRequestConfig
  ): Promise<AxiosResponse<T>> {
    return this.client.delete<T>(url, config);
  }

  async put<T>(
    url: string,
    data?: unknown,
    config?: AxiosRequestConfig
  ): Promise<AxiosResponse<T>> {
    return this.client.put<T>(url, data, config);
  }

  /**
   * Chama uma Edge Function do Supabase
   * Usa a baseURL de Functions em vez de REST
   */
  async callFunction<T>(
    functionName: string,
    data?: unknown,
    config?: AxiosRequestConfig
  ): Promise<AxiosResponse<T>> {
    const fullUrl = `${API_CONFIG.FUNCTIONS_URL}/${functionName}`;

    console.log("[ApiClient] Calling Edge Function:", {
      functionName,
      fullUrl,
      data,
    });

    // Cria uma requisição sem baseURL
    const functionsClient = axios.create({
      timeout: API_CONFIG.TIMEOUT,
      headers: {
        "Content-Type": "application/json",
        apikey: API_CONFIG.SUPABASE_ANON_KEY,
      },
    });

    // Adiciona token se disponível
    const token = localStorage.getItem(API_CONFIG.STORAGE_KEYS.ACCESS_TOKEN);
    if (token) {
      functionsClient.defaults.headers.common[
        "Authorization"
      ] = `Bearer ${token}`;
    }

    try {
      const response = await functionsClient.post<T>(fullUrl, data, config);
      console.log("[ApiClient] Edge Function Response:", {
        functionName,
        status: response.status,
        data: response.data,
      });
      return response;
    } catch (error: any) {
      console.error("[ApiClient] Edge Function Error:", {
        functionName,
        fullUrl,
        status: error?.response?.status,
        statusText: error?.response?.statusText,
        data: error?.response?.data,
        message: error?.message,
      });
      throw error;
    }
  }
}

export const apiClient = new ApiClient();
