import axios, { AxiosError, AxiosResponse } from 'axios';
import type { OffsetOrder, Portfolio } from '../types';
import { config } from '../utils/config';

// Default portfolio for fallback
const DEFAULT_PORTFOLIO: Portfolio = {
  id: 2, // Updated to use ID 2 as in the tutorial
  name: "Community Tree Planting",
  description: "A curated selection of high-impact carbon removal projects focused on carbon sequestration through tree planting.",
  projects: [
    {
      id: "tree-1",
      name: "Community Tree Planting",
      description: "Carbon sequestration through community tree planting",
      shortDescription: "Tree planting projects",
      imageUrl: "https://images.unsplash.com/photo-1513836279014-a89f7a76ae86",
      pricePerTon: 284.63,
      location: "Global",
      type: "Nature Based",
      verificationStandard: "Gold Standard",
      impactMetrics: {
        co2Reduced: 5000
      }
    }
  ],
  pricePerTon: 284.63,
  currency: 'USD'
};

// Create API client with error handling, timeout, and retry logic
const createApiClient = () => {
  if (!config.wrenApiKey) {
    console.error('Wren API token is missing! Token:', config.wrenApiKey);
    console.error('Environment:', window?.env ? JSON.stringify(window.env) : 'No window.env available');
    throw new Error('Wren API token is not configured');
  }

  console.log('[wrenClient] Creating API client with key:', config.wrenApiKey ? '********' + config.wrenApiKey.slice(-4) : 'MISSING');

  const client = axios.create({
    // Updated base URL to match the tutorial exactly
    baseURL: 'https://www.wren.co/api',
    headers: {
      'Authorization': `Bearer ${config.wrenApiKey}`,
      'Content-Type': 'application/json'
    },
    timeout: 10000, // 10 second timeout
    validateStatus: (status: number) => status >= 200 && status < 500, // Handle 4xx errors gracefully
  });

  // Add request interceptor for logging
  client.interceptors.request.use(
    (config) => {
      if (!config.headers?.Authorization) {
        throw new Error('API token is required');
      }
      console.log('[wrenClient] Making API request to:', config.url);
      return config;
    },
    (error: Error) => {
      console.error('[wrenClient] Request configuration error:', error.message);
      return Promise.reject(error);
    }
  );

  // Add response interceptor for error handling
  client.interceptors.response.use(
    (response: AxiosResponse) => {
      console.log('[wrenClient] Received API response:', response.status);
      return response;
    },
    (error: unknown) => {
      if (axios.isAxiosError(error)) {
        if (error.code === 'ECONNABORTED') {
          console.warn('[wrenClient] Request timeout, using fallback data');
          return Promise.resolve({ data: { portfolios: [DEFAULT_PORTFOLIO] } });
        }
        if (!error.response) {
          console.warn('[wrenClient] Network error, using fallback data');
          return Promise.resolve({ data: { portfolios: [DEFAULT_PORTFOLIO] } });
        }
        if (error.response.status === 401) {
          console.warn('[wrenClient] Authentication failed, using fallback data');
          return Promise.resolve({ data: { portfolios: [DEFAULT_PORTFOLIO] } });
        }
        console.error('[wrenClient] API error:', error.response?.status, error.response?.data);
      }
      return Promise.reject(error);
    }
  );

  return client;
};

// Safe error logging function that handles non-serializable objects
const logError = (error: unknown) => {
  if (error instanceof Error) {
    const errorInfo = {
      name: error.name,
      message: error.message,
      stack: error.stack
    };
    console.error('[wrenClient] API Error:', JSON.stringify(errorInfo, null, 2));
  } else {
    console.error('[wrenClient] Unknown error:', String(error));
  }
};

export async function getPortfolios(): Promise<Portfolio[]> {
  try {
    if (!config.wrenApiKey) {
      console.warn('[wrenClient] No Wren API token configured, using fallback portfolio');
      return [DEFAULT_PORTFOLIO];
    }

    console.log('[wrenClient] Getting portfolios with token:', config.wrenApiKey ? '********' + config.wrenApiKey.slice(-4) : 'MISSING');
    
    const api = createApiClient();
    // Removed the /api prefix to match the working example
    const response = await api.get('/portfolios');
    
    if (!response.data?.portfolios?.length) {
      console.warn('[wrenClient] No portfolios returned from API, using fallback');
      return [DEFAULT_PORTFOLIO];
    }

    return response.data.portfolios.map((portfolio: any) => {
      let pricePerTon = 18; // Default price based on the Wren Climate Fund average
      
      // The API returns cost_per_ton in snake_case
      if (portfolio.cost_per_ton !== undefined && portfolio.cost_per_ton !== null) {
        pricePerTon = typeof portfolio.cost_per_ton === 'number' ? portfolio.cost_per_ton : parseFloat(portfolio.cost_per_ton) || 18;
      } else if (portfolio.costPerTon !== undefined && portfolio.costPerTon !== null) {
        pricePerTon = typeof portfolio.costPerTon === 'number' ? portfolio.costPerTon : parseFloat(portfolio.costPerTon) || 18;
      } else if (portfolio.pricePerTon !== undefined && portfolio.pricePerTon !== null) {
        pricePerTon = typeof portfolio.pricePerTon === 'number' ? portfolio.pricePerTon : parseFloat(portfolio.pricePerTon) || 18;
      }

      // Convert from snake_case to camelCase for projects
      const projects = portfolio.projects?.map(project => {
        // Ensure cost_per_ton is properly mapped
        const projectPricePerTon = project.cost_per_ton !== undefined && project.cost_per_ton !== null
          ? (typeof project.cost_per_ton === 'number' ? project.cost_per_ton : parseFloat(project.cost_per_ton))
          : pricePerTon;
          
        // Ensure percentage is properly captured
        const projectPercentage = project.percentage !== undefined && project.percentage !== null
          ? (typeof project.percentage === 'number' ? project.percentage : parseFloat(project.percentage))
          : undefined;

        return {
          id: project.id || `project-${Math.random().toString(36).substring(2, 9)}`,
          name: project.name,
          description: project.description || '',
          shortDescription: project.short_description || project.description || '',
          imageUrl: project.image_url, // Map from snake_case API response
          pricePerTon: projectPricePerTon,
          percentage: projectPercentage, // Include percentage field
          // Remove fields that aren't in the API
          // The required type fields are still in the type definition for compatibility
          // but we no longer populate them with default values
          location: '',
          type: '',
          verificationStandard: '',
          impactMetrics: {
            co2Reduced: 0
          }
        };
      }) || [];
      
      return {
        id: portfolio.id,
        name: portfolio.name,
        description: portfolio.description || '',
        projects: projects,
        pricePerTon,
        currency: 'USD'
      };
    });
  } catch (error) {
    logError(error);
    console.warn('[wrenClient] Failed to fetch portfolios from API, using fallback');
    return [DEFAULT_PORTFOLIO];
  }
}

export async function createOffsetOrder(
  portfolioId: number,
  tons: number,
  dryRun: boolean = false
): Promise<OffsetOrder> {
  try {
    if (!config.wrenApiKey) {
      console.error('[wrenClient] Cannot create order - missing API token');
      throw new Error('Carbon offset service is currently unavailable. Please contact support.');
    }
    
    console.log(`[wrenClient] Creating offset order: portfolio=${portfolioId}, tons=${tons}, dryRun=${dryRun}`);
    
    const api = createApiClient();
    // Removed the /api prefix to match the working example
    const response = await api.post('/offset-orders', {
      // Using exactly the format shown in the API tutorial
      portfolioId, // Use the provided portfolio ID instead of hardcoding
      tons,
      dryRun // Use the provided dryRun parameter
    });

    // Add detailed response logging
    console.log('[wrenClient] Offset order response:', 
                response.status, 
                response.data ? 'has data' : 'no data');
    
    if (response.status === 400) {
      console.error('[wrenClient] Bad request details:', response.data);
      throw new Error(`Failed to create offset order: ${JSON.stringify(response.data)}`);
    }

    const order = response.data;
    if (!order) {
      throw new Error('Empty response received from offset order API');
    }
    
    // Log to help diagnose issues
    console.log('[wrenClient] Order data keys:', Object.keys(order).join(', '));
    if (order.portfolio) {
      console.log('[wrenClient] Portfolio data keys:', Object.keys(order.portfolio).join(', '));
    }
    
    // Get price from API response which uses cost_per_ton
    let pricePerTon = 18;
    if (order.portfolio?.cost_per_ton !== undefined) {
      pricePerTon = typeof order.portfolio.cost_per_ton === 'number' ? order.portfolio.cost_per_ton : parseFloat(order.portfolio.cost_per_ton) || 18;
    } else if (order.portfolio?.costPerTon !== undefined) {
      pricePerTon = typeof order.portfolio.costPerTon === 'number' ? order.portfolio.costPerTon : parseFloat(order.portfolio.costPerTon) || 18;
    } else if (order.portfolio?.pricePerTon !== undefined) {
      pricePerTon = typeof order.portfolio.pricePerTon === 'number' ? order.portfolio.pricePerTon : parseFloat(order.portfolio.pricePerTon) || 18;
    }

    // Create a safe method to extract properties with fallbacks
    const getSafeProp = (obj: any, prop: string, fallback: any) => {
      if (!obj) return fallback;
      return obj[prop] !== undefined ? obj[prop] : fallback;
    };
    
    // Use safe accessor to avoid undefined errors
    const portfolio = order.portfolio || {};
    
    // Adjusted to use camelCase as per API docs response format
    return {
      id: getSafeProp(order, 'id', ''),
      amountCharged: getSafeProp(order, 'amountCharged', 0),
      currency: getSafeProp(order, 'currency', 'USD'),
      tons: getSafeProp(order, 'tons', 0),
      portfolio: {
        id: getSafeProp(portfolio, 'id', 2),
        name: getSafeProp(portfolio, 'name', 'Community Tree Planting'),
        description: getSafeProp(portfolio, 'description', ''),
        projects: getSafeProp(portfolio, 'projects', []),
        pricePerTon,
        currency: getSafeProp(order, 'currency', 'USD')
      },
      status: getSafeProp(order, 'status', ''),
      createdAt: getSafeProp(order, 'createdAt', new Date().toISOString()),
      dryRun: getSafeProp(order, 'dryRun', true)
    };
  } catch (error: unknown) {
    logError(error);
    
    if (axios.isAxiosError(error)) {
      const axiosError = error as AxiosError;
      
      console.error('[wrenClient] Axios error details:', {
        status: axiosError.response?.status,
        statusText: axiosError.response?.statusText,
        data: axiosError.response?.data,
        config: {
          url: axiosError.config?.url,
          method: axiosError.config?.method,
          headers: axiosError.config?.headers ? 'Headers present' : 'No headers',
          baseURL: axiosError.config?.baseURL,
          data: axiosError.config?.data
        }
      });
      
      if (axiosError.response?.status === 400) {
        // Provide more specific error for 400 Bad Request
        const responseData = axiosError.response.data as any;
        const errorMessage = responseData?.message || responseData?.error || 'Invalid request format';
        throw new Error(`Bad request: ${errorMessage}`);
      }
      
      if (axiosError.code === 'ECONNABORTED') {
        throw new Error('Request timed out. Please try again.');
      }
      if (!axiosError.response) {
        throw new Error('Network error. Please check your connection and try again.');
      }
      if (axiosError.response.status === 401) {
        throw new Error('Carbon offset service authentication failed. Please check your API token.');
      }
    }
    
    throw new Error('Failed to create offset order. Please try again.');
  }
}
