import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { assetService, type Asset, type AssetCreate, type AssetUpdate, AssetCategory, TaskStatus } from '@/services/asset'

// Shared optimistic-update helpers for a single asset's task status, used by both
// updateTaskStatus and bulkUpdateTaskStatus — the two API calls they wrap are genuinely
// different (single-task endpoint vs. a distinct bulk endpoint), so only the per-asset
// snapshot/apply/rollback of local state is shared, not the outer functions themselves.
interface AssetTaskStatusSnapshot {
  taskStatus?: TaskStatus
  taskDetailStatus?: TaskStatus
  taskDetailTaskId?: number
}

function snapshotAssetTaskStatus(asset: Asset, taskType: string): AssetTaskStatusSnapshot {
  const taskDetail = asset.task_details?.find(task => task.task_type === taskType)
  return {
    taskStatus: asset.task_status?.[taskType],
    taskDetailStatus: taskDetail?.status,
    taskDetailTaskId: taskDetail?.task_id
  }
}

function applyAssetTaskStatus(asset: Asset, taskType: string, newStatus: TaskStatus) {
  if (asset.task_status) {
    asset.task_status[taskType] = newStatus
  }
  const taskDetail = asset.task_details?.find(task => task.task_type === taskType)
  if (taskDetail) {
    taskDetail.status = newStatus
  }
}

function rollbackAssetTaskStatus(
  asset: Asset,
  taskType: string,
  snapshot: AssetTaskStatusSnapshot,
  options: { restoreTaskId?: boolean } = {}
) {
  if (asset.task_status && snapshot.taskStatus !== undefined) {
    asset.task_status[taskType] = snapshot.taskStatus
  }

  const taskDetail = asset.task_details?.find(task => task.task_type === taskType)
  if (taskDetail && snapshot.taskDetailStatus !== undefined) {
    taskDetail.status = snapshot.taskDetailStatus
    if (options.restoreTaskId && snapshot.taskDetailTaskId !== undefined) {
      taskDetail.task_id = snapshot.taskDetailTaskId
    }
  }
}

export const useAssetsStore = defineStore('assets', () => {
  // State
  const assets = ref<Asset[]>([])
  const currentAsset = ref<Asset | null>(null)
  const isLoading = ref(false)
  const error = ref<string | null>(null)

  // Getters
  const getAssetsByCategory = computed(() => {
    return (category: AssetCategory) => assets.value.filter(asset => asset.category === category)
  })

  const getAssetById = computed(() => {
    return (id: number) => assets.value.find(asset => asset.id === id)
  })

  const assetsByCategory = computed(() => {
    const grouped: Record<AssetCategory, Asset[]> = {
      [AssetCategory.CHARACTERS]: [],
      [AssetCategory.PROPS]: [],
      [AssetCategory.SETS]: [],
      [AssetCategory.VEHICLES]: []
    }

    assets.value.forEach(asset => {
      grouped[asset.category].push(asset)
    })

    return grouped
  })

  // Actions
  const fetchAssets = async (
    projectId: number, 
    options?: {
      category?: AssetCategory
      taskStatusFilter?: string
      sortBy?: string
      sortDirection?: 'asc' | 'desc'
    }
  ) => {
    try {
      isLoading.value = true
      error.value = null
      const data = await assetService.getAssets(projectId, options)
      assets.value = data
    } catch (err) {
      error.value = err instanceof Error ? err.message : 'Failed to fetch assets'
      throw err
    } finally {
      isLoading.value = false
    }
  }

  const fetchAsset = async (assetId: number) => {
    try {
      isLoading.value = true
      error.value = null
      const data = await assetService.getAsset(assetId)
      currentAsset.value = data
      
      // Update in assets list if it exists
      const index = assets.value.findIndex(asset => asset.id === assetId)
      if (index !== -1) {
        assets.value[index] = data
      }
      
      return data
    } catch (err) {
      error.value = err instanceof Error ? err.message : 'Failed to fetch asset'
      throw err
    } finally {
      isLoading.value = false
    }
  }

  const createAsset = async (projectId: number, assetData: AssetCreate) => {
    try {
      isLoading.value = true
      error.value = null
      const newAsset = await assetService.createAsset(projectId, assetData)
      assets.value.push(newAsset)
      return newAsset
    } catch (err) {
      error.value = err instanceof Error ? err.message : 'Failed to create asset'
      throw err
    } finally {
      isLoading.value = false
    }
  }

  const updateAsset = async (assetId: number, assetData: AssetUpdate) => {
    try {
      isLoading.value = true
      error.value = null
      const updatedAsset = await assetService.updateAsset(assetId, assetData)
      
      // Update in assets list
      const index = assets.value.findIndex(asset => asset.id === assetId)
      if (index !== -1) {
        assets.value[index] = updatedAsset
      }
      
      // Update current asset if it's the same
      if (currentAsset.value?.id === assetId) {
        currentAsset.value = updatedAsset
      }
      
      return updatedAsset
    } catch (err) {
      error.value = err instanceof Error ? err.message : 'Failed to update asset'
      throw err
    } finally {
      isLoading.value = false
    }
  }

  const deleteAsset = async (assetId: number) => {
    try {
      isLoading.value = true
      error.value = null
      await assetService.deleteAsset(assetId)
      
      // Remove from assets list
      const index = assets.value.findIndex(asset => asset.id === assetId)
      if (index !== -1) {
        assets.value.splice(index, 1)
      }
      
      // Clear current asset if it's the same
      if (currentAsset.value?.id === assetId) {
        currentAsset.value = null
      }
    } catch (err) {
      error.value = err instanceof Error ? err.message : 'Failed to delete asset'
      throw err
    } finally {
      isLoading.value = false
    }
  }

  const clearAssets = () => {
    assets.value = []
    currentAsset.value = null
    error.value = null
  }

  const setCurrentAsset = (asset: Asset | null) => {
    currentAsset.value = asset
  }

  const updateTaskStatus = async (assetId: number, taskType: string, newStatus: TaskStatus) => {
    // Find the asset in the store
    const assetIndex = assets.value.findIndex(asset => asset.id === assetId)
    if (assetIndex === -1) return

    const asset = assets.value[assetIndex]

    // Store original status for rollback, then apply the optimistic update
    const snapshot = snapshotAssetTaskStatus(asset, taskType)
    applyAssetTaskStatus(asset, taskType, newStatus)

    // Update the current asset if it's the same
    if (currentAsset.value?.id === assetId) {
      currentAsset.value = { ...asset }
    }

    try {
      // Make API call to update task status
      const { taskService } = await import('@/services/task')
      
      // Get task ID from task details
      let taskId = asset.task_details?.find(task => task.task_type === taskType)?.task_id
      
      // If no task exists, create one first
      if (!taskId) {
        const newTask = await taskService.createAssetTask(assetId, taskType)
        taskId = newTask.task_id
        
        // Update task details with new task
        if (asset.task_details) {
          const existingTaskIndex = asset.task_details.findIndex(task => task.task_type === taskType)
          if (existingTaskIndex !== -1) {
            asset.task_details[existingTaskIndex].task_id = taskId
          } else {
            asset.task_details.push({
              task_type: taskType as any,
              status: newStatus,
              task_id: taskId
            })
          }
        }
      }
      
      // Update the task status via API
      if (taskId) {
        await taskService.updateTaskStatus(taskId, newStatus)
      }
    } catch (error) {
      // Rollback optimistic update on error
      rollbackAssetTaskStatus(asset, taskType, snapshot)

      // Update the current asset if it's the same
      if (currentAsset.value?.id === assetId) {
        currentAsset.value = { ...asset }
      }

      throw error
    }
  }

  const bulkUpdateTaskStatus = async (assetIds: number[], taskType: string, newStatus: TaskStatus) => {
    if (assetIds.length === 0) return

    // Store original states for rollback
    const originalStates = new Map<number, AssetTaskStatusSnapshot>()

    // Optimistic updates
    for (const assetId of assetIds) {
      const assetIndex = assets.value.findIndex(asset => asset.id === assetId)
      if (assetIndex === -1) continue

      const asset = assets.value[assetIndex]

      originalStates.set(assetId, snapshotAssetTaskStatus(asset, taskType))
      applyAssetTaskStatus(asset, taskType, newStatus)

      // Update current asset if it's the same
      if (currentAsset.value?.id === assetId) {
        currentAsset.value = { ...asset }
      }
    }

    try {
      const { taskService } = await import('@/services/task')
      const taskIds: number[] = []

      // Collect or create task IDs
      for (const assetId of assetIds) {
        const asset = assets.value.find(a => a.id === assetId)
        if (!asset) continue

        let taskId = asset.task_details?.find(task => task.task_type === taskType)?.task_id
        
        // If no task exists, create one first
        if (!taskId) {
          const newTask = await taskService.createAssetTask(assetId, taskType)
          taskId = newTask.task_id
          
          // Update task details with new task
          if (asset.task_details) {
            const existingTaskIndex = asset.task_details.findIndex(task => task.task_type === taskType)
            if (existingTaskIndex !== -1) {
              asset.task_details[existingTaskIndex].task_id = taskId
            } else {
              asset.task_details.push({
                task_type: taskType as any,
                status: newStatus,
                task_id: taskId
              })
            }
          }
        }
        
        if (taskId) {
          taskIds.push(taskId)
        }
      }

      // Bulk update task statuses via API
      if (taskIds.length > 0) {
        await taskService.bulkUpdateStatus(taskIds, newStatus)
      }
    } catch (error) {
      // Rollback all optimistic updates on error
      for (const assetId of assetIds) {
        const assetIndex = assets.value.findIndex(asset => asset.id === assetId)
        if (assetIndex === -1) continue

        const asset = assets.value[assetIndex]
        const snapshot = originalStates.get(assetId)

        if (snapshot) {
          rollbackAssetTaskStatus(asset, taskType, snapshot, { restoreTaskId: true })
        }

        // Update current asset if it's the same
        if (currentAsset.value?.id === assetId) {
          currentAsset.value = { ...asset }
        }
      }

      throw error
    }
  }

  return {
    // State
    assets,
    currentAsset,
    isLoading,
    error,
    
    // Getters
    getAssetsByCategory,
    getAssetById,
    assetsByCategory,
    
    // Actions
    fetchAssets,
    fetchAsset,
    createAsset,
    updateAsset,
    deleteAsset,
    clearAssets,
    setCurrentAsset,
    updateTaskStatus,
    bulkUpdateTaskStatus
  }
})