import type { 
  SteamCollectionItem, 
  Submission, 
  PuzzleResponse, 
  SubmissionFile,
  UserInfo
} 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
      }
    }
  }

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

  // 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
      responses: Array<{
        puzzle_id: number
        puzzle_name: string
        cost?: string
        cycles?: string
        area?: string
        needs_manual_validation?: boolean
        ocr_confidence_score?: 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?: string
      validated_cycles?: string
      validated_area?: string
    }
  ): Promise<ApiResponse<PuzzleResponse>> {
    return this.request<PuzzleResponse>(`/submissions/responses/${responseId}/validate`, {
      method: 'PUT',
      body: JSON.stringify(validationData),
    })
  }

  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')
  }
}

// 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
  ): Promise<ApiResponse<Submission>> {
    // Group files by detected puzzle
    const responsesByPuzzle: Record<string, { 
      puzzle: SteamCollectionItem | null, 
      files: SubmissionFile[] 
    }> = {}
    
    files.forEach(file => {
      if (file.ocrData?.puzzle) {
        const puzzleName = file.ocrData.puzzle
        if (!responsesByPuzzle[puzzleName]) {
          responsesByPuzzle[puzzleName] = {
            puzzle: puzzleHelpers.findPuzzleByName(puzzles, puzzleName),
            files: []
          }
        }
        responsesByPuzzle[puzzleName].files.push(file)
      }
    })

    // Create responses array
    const responses = Object.entries(responsesByPuzzle)
      .filter(([_, data]) => data.puzzle) // Only include matched puzzles
      .map(([puzzleName, data]) => {
        // Get OCR data from the first file with complete data
        const fileWithOCR = data.files.find(f => 
          f.ocrData?.cost || f.ocrData?.cycles || f.ocrData?.area
        )
        
        // Check if manual validation is needed
        const needsValidation = !fileWithOCR?.ocrData || 
          !fileWithOCR.ocrData.cost || 
          !fileWithOCR.ocrData.cycles || 
          !fileWithOCR.ocrData.area

        return {
          puzzle_id: data.puzzle!.id,
          puzzle_name: puzzleName,
          cost: fileWithOCR?.ocrData?.cost,
          cycles: fileWithOCR?.ocrData?.cycles,
          area: fileWithOCR?.ocrData?.area,
          needs_manual_validation: needsValidation,
          ocr_confidence_score: needsValidation ? 0.5 : 0.9 // Rough estimate
        }
      })

    if (responses.length === 0) {
      return {
        error: 'No valid puzzle responses found',
        status: 400
      }
    }

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

    return apiService.createSubmission({ notes, 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
  }
}
