import { APP_CONFIG } from '../utils/config';

export interface ApiResponse<T = any> {
  success: boolean;
  data?: T;
  message?: string;
}

class ApiClient {
  private baseURL: string;
  private token: string | null = null;
  private _lastTokenCheck: string | null = null;

  constructor() {
    // Always use relative path - never absolute URLs
    // Vite proxy (dev) or Apache proxy (production) will handle the routing
    let apiUrl = APP_CONFIG.API_URL || '/api';

    // If API_URL is absolute (starts with http:// or https://), extract the path
    // This handles cases where VITE_API_URL might be set to absolute URL in .env
    if (apiUrl.startsWith('http://') || apiUrl.startsWith('https://')) {
      try {
        const urlObj = new URL(apiUrl);
        apiUrl = urlObj.pathname; // Extract only the path
      } catch (e) {
        // If URL parsing fails, default to /api
        apiUrl = '/api';
      }
    }

    // Ensure baseURL doesn't have trailing slash (except root)
    if (apiUrl.endsWith('/') && apiUrl !== '/') {
      apiUrl = apiUrl.slice(0, -1);
    }

    // Ensure it starts with /
    if (!apiUrl.startsWith('/')) {
      apiUrl = '/' + apiUrl;
    }

    this.baseURL = apiUrl;

    // Load token from localStorage
    this.token = localStorage.getItem('auth_token');

    // Debug log in development

  }

  setToken(token: string | null): void {
    this.token = token;
    if (token) {
      localStorage.setItem('auth_token', token);
      if (import.meta.env?.DEV || true) {
        console.log('[API Client] Token saved to localStorage:', {
          tokenLength: token.length,
          tokenPreview: `${token.substring(0, 20)}...`,
          stored: !!localStorage.getItem('auth_token')
        });
      }
    } else {
      localStorage.removeItem('auth_token');
      if (import.meta.env?.DEV || true) {
        console.log('[API Client] Token removed from localStorage');
      }
    }
  }

  getToken(): string | null {
    const token = this.token || localStorage.getItem('auth_token');

    return token;
  }

  private async request<T>(
    endpoint: string,
    options: RequestInit = {}
  ): Promise<ApiResponse<T>> {
    // Ensure endpoint starts with /
    if (!endpoint.startsWith('/')) {
      endpoint = '/' + endpoint;
    }

    // Always use relative path from root domain (not from base path)
    // This ensures /api/... works correctly whether running from /dev/ or / in production
    // Vite proxy (dev) or Apache proxy (production) will handle routing
    let url = `${this.baseURL}${endpoint}`;

    // Force relative path - if somehow absolute URL got through, extract path
    if (url.startsWith('http://') || url.startsWith('https://')) {
      try {
        const urlObj = new URL(url);
        url = urlObj.pathname; // Extract only the path
      } catch (e) {
        url = '/api' + endpoint; // Fallback
      }
    }

    const token = this.getToken();

    // Debug log in development


    const headers: HeadersInit = {
      'Content-Type': 'application/json',
      ...options.headers,
    };

    if (token) {
      headers['Authorization'] = `Bearer ${token}`;
      // Debug: log that we're adding the header

    } else {
      // Debug: warn if no token for protected endpoint
      if (import.meta.env?.DEV || true) {
        const protectedEndpoints = ['/projects', '/assets', '/tickets', '/users'];
        if (protectedEndpoints.some(ep => endpoint.includes(ep))) {
          console.warn('[API Client] No token found for protected endpoint:', endpoint);
        }
      }
    }

    try {
      const response = await fetch(url, {
        ...options,
        headers,
      });

      // Parse response data first
      let data: any;
      try {
        data = await response.json();
      } catch {
        // If response is not JSON, create error response
        data = {
          success: false,
          message: response.statusText || `HTTP error! status: ${response.status}`,
        };
      }

      // Handle 401 (Unauthorized) gracefully - this is expected when not logged in
      // Don't log as error - just return failure response
      if (response.status === 401) {
        const isAuthMe = url.includes('/auth/me');
        const isLogin = url.includes('/auth/login');
        const isPublicEndpoint = isAuthMe || isLogin;

        // Log 401 for debugging
        if (!isPublicEndpoint) {
          console.warn('[API Client] 401 Unauthorized on protected endpoint:', {
            url,
            hasToken: !!this.token,
            tokenWasSent: !!this.token,
            responseMessage: data.message,
            isAuthEndpoint: isPublicEndpoint
          });
        }

        // Only clear token if this is an auth endpoint or if we got a specific error indicating invalid token
        // Don't clear token immediately on protected endpoints - might be a backend/proxy issue
        const shouldClearToken = isPublicEndpoint ||
          (data.message && (data.message.includes('expired') || data.message.includes('Invalid token') || data.message.includes('invalid')));

        if (shouldClearToken && this.token) {
          if (isAuthMe) {
            // For /auth/me endpoint, clear invalid token silently
            console.log('[API Client] Clearing invalid token from /auth/me response');
            this.setToken(null);
          } else if (isPublicEndpoint) {
            // For other auth endpoints, don't clear - might be login error
          } else {
            // Only clear if explicitly told token is invalid
            console.warn('[API Client] Clearing invalid token due to explicit error message:', data.message);
            this.setToken(null);

            // If we're not already on login page, redirect to login after a short delay
            if (typeof window !== 'undefined' && !window.location.pathname.includes('/login') && !window.location.hash.includes('/login')) {
              // Small delay to allow component to handle the error first
              setTimeout(() => {
                // Only redirect if still no token (avoid redirect loops)
                if (!this.getToken()) {
                  window.location.hash = '#/login';
                }
              }, 100);
            }
          }
        } else if (!isPublicEndpoint && this.token) {
          // Token exists but got 401 - might be backend/proxy issue, don't clear token
          console.warn('[API Client] Got 401 but keeping token - might be backend/proxy issue:', {
            url,
            responseMessage: data.message
          });
        }

        return {
          success: false,
          message: data.message || 'Unauthorized',
          data: null,
        } as ApiResponse<T>;
      }

      // Handle other non-OK responses
      if (!response.ok) {
        throw new Error(data.message || `HTTP error! status: ${response.status}`);
      }

      return data;
    } catch (error: any) {
      // Only log non-401 errors as actual errors
      // Suppress 401 errors for /auth/me endpoint (expected when not logged in)
      const isAuthMe = url.includes('/auth/me');
      const is401Error = error.message?.includes('Unauthorized') || error.message?.includes('401');

      if (!isAuthMe || !is401Error) {
        console.error('[API Client] Error:', {
          url,
          method: options.method || 'GET',
          error: error.message,
        });
      }
      throw error;
    }
  }

  async get<T>(endpoint: string): Promise<ApiResponse<T>> {
    const separator = endpoint.includes('?') ? '&' : '?';
    const cacheBuster = `${separator}t=${Date.now()}`;
    return this.request<T>(`${endpoint}${cacheBuster}`, { method: 'GET' });
  }

  async post<T>(endpoint: string, body?: any): Promise<ApiResponse<T>> {
    return this.request<T>(endpoint, {
      method: 'POST',
      body: body ? JSON.stringify(body) : undefined,
    });
  }

  async put<T>(endpoint: string, body?: any): Promise<ApiResponse<T>> {
    return this.request<T>(endpoint, {
      method: 'PUT',
      body: body ? JSON.stringify(body) : undefined,
    });
  }

  async delete<T>(endpoint: string): Promise<ApiResponse<T>> {
    return this.request<T>(endpoint, { method: 'DELETE' });
  }
}

export const apiClient = new ApiClient();
