import { MockAgent } from 'undici'
import { getFixture } from '../fixtures/api-responses.js'

/**
 * Centralized API mock setup following Google style guide principles.
 * Provides consistent response headers and mock configuration.
 */
export class MockAPI {
  constructor(mockPool) {
    this.mockPool = mockPool
    this.defaultHeaders = {
      'content-type': 'application/json'
    }
  }

  /**
   * Mock a successful JSON response.
   */
  mockJSON(path, method, responseBody, statusCode = 200) {
    return this.mockPool.intercept({
      path,
      method
    }).reply(statusCode, responseBody, {
      headers: this.defaultHeaders
    })
  }

  /**
   * Mock a successful response with custom headers.
   */
  mockResponse(path, method, responseBody, statusCode = 200, headers = {}) {
    return this.mockPool.intercept({
      path,
      method
    }).reply(statusCode, responseBody, {
      headers: { ...this.defaultHeaders, ...headers }
    })
  }

  /**
   * Mock an error response.
   */
  mockError(path, method, error) {
    return this.mockPool.intercept({
      path,
      method
    }).replyWithError(error)
  }

  /**
   * Mock a request with body validation.
   */
  mockJSONWithBody(path, method, expectedBody, responseBody, statusCode = 200) {
    return this.mockPool.intercept({
      path,
      method,
      body: JSON.stringify(expectedBody)
    }).reply(statusCode, responseBody, {
      headers: this.defaultHeaders
    })
  }

  // Common API mocks for FCP
  
  mockAvailability(auctions = null) {
    const response = auctions || getFixture('availability.withInstances')
    return this.mockJSON('/v2/spot/availability', 'GET', response)
  }

  mockEmptyAvailability() {
    return this.mockJSON('/v2/spot/availability', 'GET', { auctions: [] })
  }

  mockSSHKeys(keys = null) {
    const response = keys || { ssh_keys: [] }
    return this.mockJSON(`/v2/projects/${process.env.FCP_PROJECT}/ssh-keys`, 'GET', response)
  }

  mockCreateSSHKey(keyId = 'key-123') {
    return this.mockJSON(`/v2/projects/${process.env.FCP_PROJECT}/ssh-keys`, 'POST', { id: keyId }, 201)
  }

  mockBid(bidId, bidData = null) {
    const response = bidData || getFixture('bids.running')
    return this.mockJSON(`/v2/spot/bids/${bidId}`, 'GET', response)
  }

  mockCreateBid(responseData = null) {
    const response = responseData || getFixture('bids.created')
    return this.mockJSON('/v2/spot/bids', 'POST', response, 201)
  }

  mockDeleteBid(bidId) {
    return this.mockPool.intercept({
      path: `/v2/spot/bids/${bidId}`,
      method: 'DELETE'
    }).reply(204)
  }

  mockBidsList(bids = null) {
    const response = bids || getFixture('bidsList.mixed')
    return this.mockJSON(`/v2/spot/bids?project=${process.env.FCP_PROJECT}`, 'GET', response)
  }

  // Setup helpers for common test scenarios

  setupInstanceCreation(options = {}) {
    const {
      sshKeyId = 'key-123',
      auctionId = 'auction-456',
      bidId = 'bid_new_123',
      instanceType = 'gpu.a100.1x',
      region = 'us-west-2'
    } = options

    // Mock availability with matching auction
    const availability = {
      auctions: [{
        id: auctionId,
        instance_type: instanceType,
        region: region,
        price: 25.60,
        quantity: 5,
        gpu_count: 1
      }]
    }

    this.mockSSHKeys()
    this.mockCreateSSHKey(sshKeyId)
    this.mockAvailability(availability)
    
    // Mock bid creation with expected body
    this.mockJSONWithBody('/v2/spot/bids', 'POST', {
      project: process.env.FCP_PROJECT,
      auction: auctionId,
      launch_specification: {
        ssh_keys: [sshKeyId]
      }
    }, { id: bidId }, 201)

    return { sshKeyId, auctionId, bidId }
  }

  setupInstanceCreationWithRegion(instanceType, region, auctionId) {
    const auctions = [
      {
        id: 'auction-west',
        instance_type: instanceType,
        region: 'us-west-2',
        price: 25.60,
        quantity: 5
      },
      {
        id: 'auction-east',
        instance_type: instanceType,
        region: 'us-east-1',
        price: 25.60,
        quantity: 5
      }
    ]

    this.mockAvailability({ auctions })
    this.mockSSHKeys()
    this.mockCreateSSHKey('key-123')
    this.mockAvailability({ auctions })

    // Find the correct auction for the region
    const selectedAuction = region === 'us-east-1' ? 'auction-east' : 'auction-west'

    this.mockJSONWithBody('/v2/spot/bids', 'POST', {
      project: process.env.FCP_PROJECT,
      auction: selectedAuction,
      launch_specification: {
        ssh_keys: ['key-123']
      }
    }, { id: 'bid-789' }, 201)
  }
}

/**
 * Create a mock API helper with proper setup and teardown.
 */
export function createMockAPI(mockAgent) {
  const mockPool = mockAgent.get('https://api.mlfoundry.com')
  return new MockAPI(mockPool)
}