import { apiClient } from './api'

export interface TaskStatusInfo {
  task_type: string
  status: TaskStatus
  task_id?: number
  assigned_user_id?: number
}

export interface Shot {
  id: number
  project_id: number
  name: string
  description?: string
  frame_start: number
  frame_end: number
  status: ShotStatus
  episode_id: number
  created_at: string
  updated_at: string
  task_count: number
  task_status?: Record<string, TaskStatus>
  task_details?: TaskStatusInfo[]
  task_ids?: Record<string, number>
  // Optional computed fields for display
  project_name?: string
  // Soft deletion fields
  deleted_at?: string | null
  deleted_by?: number | null
  deleted_by_name?: string | null
}

export interface ShotCreate {
  name: string
  project_id?: number  // Optional, derived from episode if not provided
  description?: string
  frame_start?: number
  frame_end?: number
  status?: ShotStatus
}

export interface ShotUpdate {
  name?: string
  project_id?: number  // Optional, for validation consistency
  description?: string
  frame_start?: number
  frame_end?: number
  status?: ShotStatus
}

export enum ShotStatus {
  NOT_STARTED = 'not_started',
  IN_PROGRESS = 'in_progress',
  ON_HOLD = 'on_hold',
  COMPLETED = 'completed',
  APPROVED = 'approved'
}

export enum TaskStatus {
  NOT_STARTED = 'not_started',
  IN_PROGRESS = 'in_progress',
  SUBMITTED = 'submitted',
  APPROVED = 'approved',
  RETAKE = 'retake'
}

export interface BulkShotCreate {
  name_prefix: string
  shot_count: number
  start_number?: number
  number_padding?: number
  frame_start?: number
  frame_end?: number
  description_template?: string
  create_default_tasks?: boolean
  task_types?: string[]
}

export interface ShotListOptions {
  episodeId?: number
  projectId?: number  // Optional project filter for enhanced querying
  taskStatusFilter?: string
  sortBy?: string
  sortDirection?: 'asc' | 'desc'
  includeDeleted?: boolean  // Include soft-deleted shots
}

export interface ShotDeletionInfo {
  shot_id: number
  shot_name: string
  episode_name: string
  project_name: string
  
  // Counts of items that will be marked as deleted
  task_count: number
  submission_count: number
  attachment_count: number
  note_count: number
  review_count: number
  
  // File information (preserved, not deleted)
  total_file_size: number
  file_count: number
  
  // Affected users
  affected_users: Array<{
    id: number
    name: string
    email: string
    role: string
    task_count: number
    submission_count: number
    note_count: number
    last_activity_date?: string
  }>
  
  // Timestamps
  last_activity_date?: string
  created_at: string
  
  // Legacy field for backward compatibility
  tasks: Array<{
    id: number
    name: string
    task_type: string
    status: TaskStatus
    assigned_user?: {
      id: number
      email: string
      name?: string
    }
  }>
}

export interface SoftDeletionError extends Error {
  code: 'SHOT_NOT_FOUND' | 'ALREADY_DELETED' | 'PERMISSION_DENIED' | 'TRANSACTION_FAILED'
  shotId: number
  details?: string
}

export interface RecoveryError extends Error {
  code: 'SHOT_NOT_DELETED' | 'ALREADY_ACTIVE' | 'PERMISSION_DENIED' | 'RECOVERY_FAILED'
  shotId: number
  details?: string
}

export interface ProjectValidationError extends Error {
  code: 'PROJECT_EPISODE_MISMATCH' | 'INVALID_PROJECT_ID' | 'PROJECT_SCOPED_NAME_CONFLICT'
  shotId?: number
  projectId?: number
  episodeId?: number
  shotName?: string
  details?: string
}

class ShotService {
  async getShots(options: ShotListOptions = {}): Promise<Shot[]> {
    const params = new URLSearchParams()
    if (options.episodeId) {
      params.append('episode_id', options.episodeId.toString())
    }
    if (options.projectId) {
      params.append('project_id', options.projectId.toString())
    }
    if (options.taskStatusFilter) {
      params.append('task_status_filter', options.taskStatusFilter)
    }
    if (options.sortBy) {
      params.append('sort_by', options.sortBy)
    }
    if (options.sortDirection) {
      params.append('sort_direction', options.sortDirection)
    }
    if (options.includeDeleted) {
      params.append('include_deleted', options.includeDeleted.toString())
    }
    
    try {
      const response = await apiClient.get(`/shots/?${params}`)
      // Ensure all shots have project_id in response
      return response.data.map((shot: Shot) => ({
        ...shot,
        project_id: shot.project_id || 0 // Fallback for backward compatibility
      }))
    } catch (error: any) {
      if (error.response?.status === 400 && error.response?.data?.detail?.includes('project')) {
        const validationError: ProjectValidationError = new Error(error.response.data.detail) as ProjectValidationError
        validationError.code = 'INVALID_PROJECT_ID'
        validationError.projectId = options.projectId
        throw validationError
      }
      throw error
    }
  }

  async getShotsByProject(projectId: number, options: Omit<ShotListOptions, 'projectId'> = {}): Promise<Shot[]> {
    return this.getShots({ ...options, projectId })
  }

  async getShot(shotId: number): Promise<Shot> {
    try {
      const response = await apiClient.get(`/shots/${shotId}`)
      // Ensure shot has project_id in response
      return {
        ...response.data,
        project_id: response.data.project_id || 0 // Fallback for backward compatibility
      }
    } catch (error: any) {
      if (error.response?.status === 400 && error.response?.data?.detail?.includes('project')) {
        const validationError: ProjectValidationError = new Error(error.response.data.detail) as ProjectValidationError
        validationError.code = 'INVALID_PROJECT_ID'
        validationError.shotId = shotId
        throw validationError
      }
      throw error
    }
  }

  async createShot(episodeId: number, data: ShotCreate): Promise<Shot> {
    try {
      const response = await apiClient.post(`/shots/?episode_id=${episodeId}`, data)
      // Ensure created shot has project_id in response
      return {
        ...response.data,
        project_id: response.data.project_id || 0 // Fallback for backward compatibility
      }
    } catch (error: any) {
      if (error.response?.status === 400) {
        const errorDetail = error.response.data?.detail || ''
        
        if (errorDetail.includes('project') && errorDetail.includes('episode')) {
          const validationError: ProjectValidationError = new Error(errorDetail) as ProjectValidationError
          validationError.code = 'PROJECT_EPISODE_MISMATCH'
          validationError.episodeId = episodeId
          validationError.projectId = data.project_id
          throw validationError
        }
        
        if (errorDetail.includes('already exists') || errorDetail.includes('duplicate')) {
          const validationError: ProjectValidationError = new Error(errorDetail) as ProjectValidationError
          validationError.code = 'PROJECT_SCOPED_NAME_CONFLICT'
          validationError.shotName = data.name
          validationError.projectId = data.project_id
          throw validationError
        }
        
        if (errorDetail.includes('project')) {
          const validationError: ProjectValidationError = new Error(errorDetail) as ProjectValidationError
          validationError.code = 'INVALID_PROJECT_ID'
          validationError.projectId = data.project_id
          throw validationError
        }
      }
      throw error
    }
  }

  async updateShot(shotId: number, data: ShotUpdate): Promise<Shot> {
    try {
      const response = await apiClient.put(`/shots/${shotId}`, data)
      // Ensure updated shot has project_id in response
      return {
        ...response.data,
        project_id: response.data.project_id || 0 // Fallback for backward compatibility
      }
    } catch (error: any) {
      if (error.response?.status === 400) {
        const errorDetail = error.response.data?.detail || ''
        
        if (errorDetail.includes('project') && errorDetail.includes('episode')) {
          const validationError: ProjectValidationError = new Error(errorDetail) as ProjectValidationError
          validationError.code = 'PROJECT_EPISODE_MISMATCH'
          validationError.shotId = shotId
          validationError.projectId = data.project_id
          throw validationError
        }
        
        if (errorDetail.includes('already exists') || errorDetail.includes('duplicate')) {
          const validationError: ProjectValidationError = new Error(errorDetail) as ProjectValidationError
          validationError.code = 'PROJECT_SCOPED_NAME_CONFLICT'
          validationError.shotId = shotId
          validationError.shotName = data.name
          validationError.projectId = data.project_id
          throw validationError
        }
        
        if (errorDetail.includes('project')) {
          const validationError: ProjectValidationError = new Error(errorDetail) as ProjectValidationError
          validationError.code = 'INVALID_PROJECT_ID'
          validationError.shotId = shotId
          validationError.projectId = data.project_id
          throw validationError
        }
      }
      throw error
    }
  }

  async getShotDeletionInfo(shotId: number): Promise<ShotDeletionInfo> {
    try {
      const response = await apiClient.get(`/shots/${shotId}/deletion-info`)
      return response.data
    } catch (error: any) {
      if (error.response?.status === 404) {
        const deletionError: SoftDeletionError = new Error('Shot not found') as SoftDeletionError
        deletionError.code = 'SHOT_NOT_FOUND'
        deletionError.shotId = shotId
        throw deletionError
      }
      if (error.response?.status === 410) {
        const deletionError: SoftDeletionError = new Error('Shot already deleted') as SoftDeletionError
        deletionError.code = 'ALREADY_DELETED'
        deletionError.shotId = shotId
        throw deletionError
      }
      if (error.response?.status === 403) {
        const deletionError: SoftDeletionError = new Error('Permission denied') as SoftDeletionError
        deletionError.code = 'PERMISSION_DENIED'
        deletionError.shotId = shotId
        throw deletionError
      }
      throw error
    }
  }

  async deleteShot(shotId: number): Promise<void> {
    try {
      // Use soft deletion by default - no force parameter needed
      await apiClient.delete(`/shots/${shotId}`)
    } catch (error: any) {
      if (error.response?.status === 404) {
        const deletionError: SoftDeletionError = new Error('Shot not found') as SoftDeletionError
        deletionError.code = 'SHOT_NOT_FOUND'
        deletionError.shotId = shotId
        throw deletionError
      }
      if (error.response?.status === 410) {
        const deletionError: SoftDeletionError = new Error('Shot already deleted') as SoftDeletionError
        deletionError.code = 'ALREADY_DELETED'
        deletionError.shotId = shotId
        throw deletionError
      }
      if (error.response?.status === 403) {
        const deletionError: SoftDeletionError = new Error('Permission denied') as SoftDeletionError
        deletionError.code = 'PERMISSION_DENIED'
        deletionError.shotId = shotId
        throw deletionError
      }
      if (error.response?.status === 500) {
        const deletionError: SoftDeletionError = new Error('Transaction failed during deletion') as SoftDeletionError
        deletionError.code = 'TRANSACTION_FAILED'
        deletionError.shotId = shotId
        deletionError.details = error.response?.data?.detail || 'Database transaction failed'
        throw deletionError
      }
      throw error
    }
  }

  async recoverShot(shotId: number): Promise<void> {
    try {
      await apiClient.post(`/admin/shots/${shotId}/recover`)
    } catch (error: any) {
      if (error.response?.status === 404) {
        const recoveryError: RecoveryError = new Error('Shot not found in recovery data') as RecoveryError
        recoveryError.code = 'SHOT_NOT_DELETED'
        recoveryError.shotId = shotId
        throw recoveryError
      }
      if (error.response?.status === 409) {
        const recoveryError: RecoveryError = new Error('Shot is already active') as RecoveryError
        recoveryError.code = 'ALREADY_ACTIVE'
        recoveryError.shotId = shotId
        throw recoveryError
      }
      if (error.response?.status === 403) {
        const recoveryError: RecoveryError = new Error('Permission denied for recovery operation') as RecoveryError
        recoveryError.code = 'PERMISSION_DENIED'
        recoveryError.shotId = shotId
        throw recoveryError
      }
      if (error.response?.status === 500) {
        const recoveryError: RecoveryError = new Error('Recovery operation failed') as RecoveryError
        recoveryError.code = 'RECOVERY_FAILED'
        recoveryError.shotId = shotId
        recoveryError.details = error.response?.data?.detail || 'Recovery transaction failed'
        throw recoveryError
      }
      throw error
    }
  }

  async bulkCreateShots(episodeId: number, data: BulkShotCreate): Promise<{ created_shots: Shot[], created_tasks_count: number, message: string }> {
    try {
      const response = await apiClient.post(`/shots/bulk/?episode_id=${episodeId}`, data)
      // Ensure all created shots have project_id in response
      const result = response.data
      result.created_shots = result.created_shots.map((shot: Shot) => ({
        ...shot,
        project_id: shot.project_id || 0 // Fallback for backward compatibility
      }))
      return result
    } catch (error: any) {
      if (error.response?.status === 400) {
        const errorDetail = error.response.data?.detail || ''
        
        if (errorDetail.includes('project') && errorDetail.includes('episode')) {
          const validationError: ProjectValidationError = new Error(errorDetail) as ProjectValidationError
          validationError.code = 'PROJECT_EPISODE_MISMATCH'
          validationError.episodeId = episodeId
          throw validationError
        }
        
        if (errorDetail.includes('already exists') || errorDetail.includes('duplicate')) {
          const validationError: ProjectValidationError = new Error(errorDetail) as ProjectValidationError
          validationError.code = 'PROJECT_SCOPED_NAME_CONFLICT'
          validationError.shotName = data.name_prefix
          throw validationError
        }
        
        if (errorDetail.includes('project')) {
          const validationError: ProjectValidationError = new Error(errorDetail) as ProjectValidationError
          validationError.code = 'INVALID_PROJECT_ID'
          validationError.episodeId = episodeId
          throw validationError
        }
      }
      throw error
    }
  }
}

export const shotService = new ShotService()