import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';

export interface GraphQLConfig {
  apiUrl: string;
  authorizationKey?: string;
  headers?: Record<string, string>;
}

export interface EventTableData {
  block_height: string;
  data: string;
  epoch: string;
  event_name: string;
  timestamp: string;
  version: string;
}

export interface GraphQLResponse<T> {
  data: T;
  errors?: any[];
}

export interface EventsQueryResponse {
  event_table: EventTableData[];
}

export class GraphQLClient {
  private client: AxiosInstance;
  private config: GraphQLConfig;

  constructor(config: GraphQLConfig) {
    this.config = config;
    
    const axiosConfig: AxiosRequestConfig = {
      baseURL: config.apiUrl,
      headers: {
        'Content-Type': 'application/json',
        ...config.headers,
      },
    };

    // Add authorization header if provided
    if (config.authorizationKey) {
      axiosConfig.headers = {
        ...axiosConfig.headers,
        // 'Authorization': "Bearer " + config.authorizationKey,
        'x-hasura-admin-secret': config.authorizationKey,
      };
    }

    this.client = axios.create(axiosConfig);
  }

  /**
   * Execute a GraphQL query
   */
  async query<T = any>(query: string, variables?: Record<string, any>): Promise<GraphQLResponse<T>> {
    try {
      const response = await this.client.post('', {
        query,
        variables,
      });

      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error)) {
        console.log(error);
        throw new Error(`GraphQL request failed: ${error.response?.data?.message || error.message}`);
      }
      throw error;
    }
  }

  /**
   * Get events with pagination
   */
  async getEvents(
    version: string = "0",
    limit: number = 100
  ): Promise<EventTableData[]> {
    const whereClause: any = {};
    
    if (version !== "0") {
      whereClause.version = { _gt: version };
    }

    const query = `
      query GetEvents($where: event_table_bool_exp, $limit: Int!) {
        event_table(
          where: $where,
          limit: $limit
        ) {
          block_height
          data
          epoch
          event_name
          timestamp
          version
        }
      }
    `;

    const variables: any = { limit };
    
    if (Object.keys(whereClause).length > 0) {
      variables.where = whereClause;
    }

    const response = await this.query<EventsQueryResponse>(query, variables);
    
    if (response.errors) {
      throw new Error(`GraphQL errors: ${JSON.stringify(response.errors)}`);
    }

    return response.data.event_table;
  }

  /**
   * Get events with custom query
   */
  async getEventsWithCustomQuery(
    query: string, 
    variables?: Record<string, any>
  ): Promise<any> {
    const response = await this.query(query, variables);
    
    if (response.errors) {
      throw new Error(`GraphQL errors: ${JSON.stringify(response.errors)}`);
    }

    return response.data;
  }

  /**
   * Update the configuration
   */
  updateConfig(newConfig: Partial<GraphQLConfig>): void {
    this.config = { ...this.config, ...newConfig };
    
    // Recreate axios instance with new config
    const axiosConfig: AxiosRequestConfig = {
      baseURL: this.config.apiUrl,
      headers: {
        'Content-Type': 'application/json',
        ...this.config.headers,
      },
    };

    if (this.config.authorizationKey) {
      axiosConfig.headers = {
        ...axiosConfig.headers,
        'Authorization': this.config.authorizationKey,
      };
    }

    this.client = axios.create(axiosConfig);
  }

  /**
   * Get current configuration
   */
  getConfig(): GraphQLConfig {
    return { ...this.config };
  }
} 