import { BaseEndpoint } from '../base';
import { CreateLogRequest, BatchLogRequest, BatchLogResponse, GetLogsRequest, PaginatedLogResponse, GetLatestLogsRequest, LatestLogsResponse, GetLogByIdRequest, LogResponse } from './types';
import { InvalidRequestError, AuthenticationError, NotFoundError, ServerError, BATCH_SIZE_LIMIT } from '../../errors';

export class LogsEndpoint extends BaseEndpoint {
  constructor(client: any) {
    super(client, '/api/logs');
  }

  private validateRequiredKeys(data: { organization_apikey?: string; app_apikey?: string }) {
    if (!data.organization_apikey) {
      throw new InvalidRequestError('organization_apikey is required');
    }
    if (!data.app_apikey) {
      throw new InvalidRequestError('app_apikey is required');
    }
  }

  private validateTimestamp(timestamp: string) {
    if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z$/.test(timestamp)) {
      throw new InvalidRequestError('timestamp must be in ISO 8601 format');
    }
  }

  /**
   * Create a log entry
   * @param data - The log creation request
   * @returns Promise that resolves if the log is created (201)
   * @throws {InvalidRequestError} If required fields are missing or invalid
   * @throws {AuthenticationError} If API keys are invalid
   * @throws {ServerError} If server encounters an error
   */
  async createLog(data: CreateLogRequest): Promise<void> {
    this.validateRequiredKeys(data);
    this.validateTimestamp(data.log_entry.timestamp);
    
    try {
      await this.post<void>('', data);
    } catch (error: any) {
      if (error.response?.status === 400) {
        throw new InvalidRequestError(error.response.data?.message || 'Invalid request');
      }
      if (error.response?.status === 401) {
        throw new AuthenticationError('Invalid API keys');
      }
      if (error.response?.status === 500) {
        throw new ServerError('Internal server error');
      }
      throw error;
    }
  }

  /**
   * Create a batch of log entries
   * @param data - The batch log creation request
   * @returns Promise with the batch log response
   * @throws {InvalidRequestError} If batch size exceeds limit or required fields are missing
   * @throws {AuthenticationError} If API keys are invalid
   * @throws {ServerError} If server encounters an error
   */
  async createBatchLogs(data: BatchLogRequest): Promise<BatchLogResponse> {
    this.validateRequiredKeys(data);
    
    if (data.logs.length > BATCH_SIZE_LIMIT) {
      throw new InvalidRequestError(`Batch size cannot exceed ${BATCH_SIZE_LIMIT} logs`);
    }

    data.logs.forEach(log => {
      this.validateTimestamp(log.timestamp);
    });

    try {
      return await this.post<BatchLogResponse>('/batch', data);
    } catch (error: any) {
      if (error.response?.status === 400) {
        throw new InvalidRequestError(error.response.data?.message || 'Invalid request');
      }
      if (error.response?.status === 401) {
        throw new AuthenticationError('Invalid API keys');
      }
      if (error.response?.status === 500) {
        throw new ServerError('Internal server error');
      }
      throw error;
    }
  }

  /**
   * Get logs for a specific item
   * @param data - The get logs request parameters
   * @returns Promise with the paginated log response
   * @throws {InvalidRequestError} If required fields are missing
   * @throws {AuthenticationError} If API keys are invalid
   * @throws {ServerError} If server encounters an error
   */
  async getLogs(data: GetLogsRequest): Promise<PaginatedLogResponse> {
    this.validateRequiredKeys(data);
    
    if (data.before) this.validateTimestamp(data.before);
    if (data.after) this.validateTimestamp(data.after);

    try {
      return await this.get<PaginatedLogResponse>('', { params: data });
    } catch (error: any) {
      if (error.response?.status === 400) {
        throw new InvalidRequestError(error.response.data?.message || 'Invalid request');
      }
      if (error.response?.status === 401) {
        throw new AuthenticationError('Invalid API keys');
      }
      if (error.response?.status === 500) {
        throw new ServerError('Internal server error');
      }
      throw error;
    }
  }

  /**
   * Get the latest logs for a specific item
   * @param data - The get latest logs request parameters
   * @returns Promise with the latest logs response
   * @throws {InvalidRequestError} If required fields are missing
   * @throws {AuthenticationError} If API keys are invalid
   * @throws {ServerError} If server encounters an error
   */
  async getLatestLogs(data: GetLatestLogsRequest): Promise<LatestLogsResponse> {
    this.validateRequiredKeys(data);

    try {
      return await this.get<LatestLogsResponse>('/latest', { params: data });
    } catch (error: any) {
      if (error.response?.status === 400) {
        throw new InvalidRequestError(error.response.data?.message || 'Invalid request');
      }
      if (error.response?.status === 401) {
        throw new AuthenticationError('Invalid API keys');
      }
      if (error.response?.status === 500) {
        throw new ServerError('Internal server error');
      }
      throw error;
    }
  }

  /**
   * Get a specific log by ID
   * @param id - The log ID
   * @param data - The get log by ID request parameters
   * @returns Promise with the log response
   * @throws {InvalidRequestError} If required fields are missing
   * @throws {AuthenticationError} If API keys are invalid
   * @throws {NotFoundError} If log is not found
   * @throws {ServerError} If server encounters an error
   */
  async getLogById(id: number, data: GetLogByIdRequest): Promise<LogResponse> {
    this.validateRequiredKeys(data);

    try {
      return await this.get<LogResponse>(`/${id}`, { params: data });
    } catch (error: any) {
      if (error.response?.status === 400) {
        throw new InvalidRequestError(error.response.data?.message || 'Invalid request');
      }
      if (error.response?.status === 401) {
        throw new AuthenticationError('Invalid API keys');
      }
      if (error.response?.status === 404) {
        throw new NotFoundError(`Log with ID ${id} not found`);
      }
      if (error.response?.status === 500) {
        throw new ServerError('Internal server error');
      }
      throw error;
    }
  }
} 