import type {
  Game,
  SteamCollection,
  SteamCollectionItem,
  Submission,
  PuzzleResponse,
  SubmissionFile,
  UserInfo,
  TournamentSubmissions,
  TournamentPuzzleResults,
  Market,
  UserBet
} from '../types'

// API Configuration
const API_BASE_URL = '/api'

// API Response Types
interface ApiResponse<T> {
  data?: T
  error?: string
  status: number
}

interface PaginatedResponse<T> {
  items: T[]
  count: number
}

interface SubmissionStats {
  total_submissions: number
  total_responses: number
  needs_validation: number
  validated_submissions: number
  validation_rate: number
}

// API Service Class
export class ApiService {
  private async request<T>(
    endpoint: string,
    options: RequestInit = {}
  ): Promise<ApiResponse<T>> {
    try {
      const response = await fetch(`${API_BASE_URL}${endpoint}`, {
        headers: {
          'Content-Type': 'application/json',
          ...options.headers,
        },
        ...options,
      })

      const data = await response.json()

      if (!response.ok) {
        return {
          error: data.detail || `HTTP ${response.status}`,
          status: response.status
        }
      }

      return {
        data,
        status: response.status
      }
    } catch (error) {
      return {
        error: error instanceof Error ? error.message : 'Network error',
        status: 0
      }
    }
  }

  private async uploadRequest<T>(
    endpoint: string,
    formData: FormData
  ): Promise<ApiResponse<T>> {
    try {
      const response = await fetch(`${API_BASE_URL}${endpoint}`, {
        method: 'POST',
        body: formData,
      })

      const data = await response.json()

      if (!response.ok) {
        return {
          error: data.detail || `HTTP ${response.status}`,
          status: response.status
        }
      }

      return {
        data,
        status: response.status
      }
    } catch (error) {
      return {
        error: error instanceof Error ? error.message : 'Network error',
        status: 0
      }
    }
  }

  // Games endpoint
  async getGames(): Promise<ApiResponse<Game[]>> {
    return this.request<Game[]>('/games/')
  }

  // Puzzle endpoints
  async getPuzzles(): Promise<ApiResponse<SteamCollectionItem[]>> {
    return this.request<SteamCollectionItem[]>('/submissions/puzzles')
  }

  async getCollection(): Promise<ApiResponse<SteamCollection>> {
    return this.request<SteamCollection>('/submissions/collection')
  }

  async getTopSubmissions(limit = 5): Promise<ApiResponse<TournamentSubmissions>> {
    return this.request<TournamentSubmissions>(`/results/top-submissions?limit=${limit}`)
  }

  async getPuzzleResults(limit = 5): Promise<ApiResponse<TournamentPuzzleResults>> {
    return this.request<TournamentPuzzleResults>(`/results/puzzle-results?limit=${limit}`)
  }

  // Submission endpoints
  async getSubmissions(limit = 20, offset = 0): Promise<ApiResponse<PaginatedResponse<Submission>>> {
    return this.request<PaginatedResponse<Submission>>(
      `/submissions/submissions?limit=${limit}&offset=${offset}`
    )
  }

  async getSubmission(id: string): Promise<ApiResponse<Submission>> {
    return this.request<Submission>(`/submissions/submissions/${id}`)
  }

  async createSubmission(
    submissionData: {
      notes?: string
      manual_validation_requested?: boolean
      responses: Array<{
        puzzle_id: number
        puzzle_name: string
        cost?: number
        cycles?: number
        area?: number
        needs_manual_validation?: boolean
        ocr_confidence_cost?: number
        ocr_confidence_cycles?: number
        ocr_confidence_area?: number
      }>
    },
    files: File[]
  ): Promise<ApiResponse<Submission>> {
    const formData = new FormData()

    // Add JSON data
    formData.append('data', JSON.stringify(submissionData))

    // Add files
    files.forEach((file) => {
      formData.append('files', file)
    })

    return this.uploadRequest<Submission>('/submissions/submissions', formData)
  }

  // Admin endpoints (require staff permissions)
  async validateResponse(
    responseId: number,
    validationData: {
      validated_cost?: number
      validated_cycles?: number
      validated_area?: number
    }
  ): Promise<ApiResponse<PuzzleResponse>> {
    return this.request<PuzzleResponse>(`/submissions/responses/${responseId}/validate`, {
      method: 'PUT',
      body: JSON.stringify(validationData),
    })
  }

  async autoValidateResponses(responseId: number): Promise<ApiResponse<PuzzleResponse>> {
    return this.request<PuzzleResponse>(`/submissions/responses/${responseId}/validate/auto`, {
      method: 'PUT',
    })
  }

  async getResponsesNeedingValidation(): Promise<ApiResponse<PuzzleResponse[]>> {
    return this.request<PuzzleResponse[]>('/submissions/responses/needs-validation')
  }

  async validateSubmission(submissionId: string): Promise<ApiResponse<Submission>> {
    return this.request<Submission>(`/submissions/submissions/${submissionId}/validate`, {
      method: 'POST',
    })
  }

  async deleteSubmission(submissionId: string): Promise<ApiResponse<{ detail: string }>> {
    return this.request<{ detail: string }>(`/submissions/submissions/${submissionId}`, {
      method: 'DELETE',
    })
  }

  // Statistics endpoint
  async getStats(): Promise<ApiResponse<SubmissionStats>> {
    return this.request<SubmissionStats>('/submissions/stats')
  }

  // Health check
  async healthCheck(): Promise<ApiResponse<{ status: string; service: string }>> {
    return this.request<{ status: string; service: string }>('/health')
  }

  // User info
  async getUserInfo(): Promise<ApiResponse<UserInfo>> {
    return this.request<UserInfo>('/user')
  }

  // Market endpoints
  async getMarkets(): Promise<ApiResponse<Market[]>> {
    return this.request<Market[]>('/market/')
  }

  async placeBet(marketUuid: string, betData: {
    option_uuid: string
    amount: number
  }): Promise<ApiResponse<UserBet>> {
    return this.request<UserBet>(`/market/${marketUuid}/bets`, {
      method: 'POST',
      body: JSON.stringify(betData),
    })
  }

  async getUserBets(): Promise<ApiResponse<UserBet[]>> {
    return this.request<UserBet[]>('/market/user/bets')
  }

  async closeMarket(marketUuid: string): Promise<ApiResponse<{ status: string }>> {
    return this.request<{ status: string }>(`/market/${marketUuid}/actions/close`, {
      method: 'POST',
    })
  }

  async resolveMarket(marketUuid: string, winningOptionUuid: string): Promise<ApiResponse<Market>> {
    return this.request<Market>(`/market/${marketUuid}/actions/resolve`, {
      method: 'POST',
      body: JSON.stringify({ winning_option_uuid: winningOptionUuid }),
    })
  }
}

// Singleton instance
export const apiService = new ApiService()

// Helper functions for common operations
export const puzzleHelpers = {
  async loadPuzzles(): Promise<SteamCollectionItem[]> {
    const response = await apiService.getPuzzles()
    if (response.error) {
      console.error('Failed to load puzzles:', response.error)
      return []
    }
    return response.data || []
  },

  findPuzzleByName(puzzles: SteamCollectionItem[], name: string): SteamCollectionItem | null {
    if (!name) return null

    // Try exact match first
    let match = puzzles.find(p =>
      p.title.toLowerCase() === name.toLowerCase()
    )

    if (!match) {
      // Try partial match
      match = puzzles.find(p =>
        p.title.toLowerCase().includes(name.toLowerCase()) ||
        name.toLowerCase().includes(p.title.toLowerCase())
      )
    }

    return match || null
  }
}

export const submissionHelpers = {
  async createFromFiles(
    files: SubmissionFile[],
    puzzles: SteamCollectionItem[],
    notes?: string,
    manualValidationRequested?: boolean
  ): Promise<ApiResponse<Submission>> {

    const responses = files.map(item => {

      const puzzle = puzzleHelpers.findPuzzleByName(puzzles, item.ocrData?.puzzle || '')
      if (!puzzle) { return }
      return {
        puzzle_id: puzzle.id,
        puzzle_name: item.ocrData?.puzzle || '',
        cost: item.ocrData?.cost,
        cycles: item.ocrData?.cycles,
        area: item.ocrData?.area,
        needs_manual_validation: (item.ocrData?.confidence.overall ?? 0) <= 0.8,
        ocr_confidence_cost: item.ocrData?.confidence?.cost || 0.0,
        ocr_confidence_cycles: item.ocrData?.confidence?.cycles || 0.0,
        ocr_confidence_area: item.ocrData?.confidence?.area || 0.0
      }
    }).filter(item => item !== undefined)

    // Extract actual File objects for upload
    const fileObjects = files.map(f => f.file)

    return apiService.createSubmission({
      notes,
      manual_validation_requested: manualValidationRequested,
      responses
    }, fileObjects)
  },

  async loadSubmissions(limit = 20, offset = 0): Promise<Submission[]> {
    const response = await apiService.getSubmissions(limit, offset)
    if (response.error) {
      console.error('Failed to load submissions:', response.error)
      return []
    }
    return response.data?.items || []
  }
}

// Error handling utilities
export const errorHelpers = {
  getErrorMessage(error: unknown): string {
    if (typeof error === 'string') return error
    if (error instanceof Error) return error.message
    if (typeof error === 'object' && error !== null && 'detail' in error) {
      return String((error as any).detail)
    }
    return 'An unknown error occurred'
  },

  isNetworkError(error: unknown): boolean {
    return typeof error === 'string' && error.includes('Network')
  },

  isValidationError(status: number): boolean {
    return status === 400
  },

  isAuthError(status: number): boolean {
    return status === 401 || status === 403
  }
}
