import {
    apiTemplateToTemplate,
    apiTemplateWithAttributesToTemplate,
    copyTemplateApi,
    CopyTemplateInput,
    PatchTemplateInput,
    createTemplateApi,
    deleteTemplateApi,
    getTemplateApi,
    getTemplatesApi,
    patchTemplateApi,
    templateToCreateInput,
    templateToPatchInput,
} from '@/entity/template/api/templateApiService'
import { Template } from '@/type/template'
import {
    QueryClient,
    useMutation,
    useQuery,
    useQueryClient,
} from '@tanstack/react-query'
import React, { createContext, ReactNode, useContext, useMemo } from 'react'

export const queryClient = new QueryClient()

interface TemplateContextType {
  templates: Template[]
  isLoading: boolean
  error: Error | null
  refetchTemplates: () => void
  addTemplate: (
    data: Omit<Template, 'id' | 'createdAt' | 'updatedAt'>,
    attributes?: Array<{ attributeId: string; value: string | null }>
  ) => Promise<Template>
  updateTemplate: (
    template: Template,
    attributes?: Array<{ attributeId: string; value: string | null }>
  ) => Promise<Template>
  deleteTemplate: (id: string) => Promise<string>
  copyTemplate: (
    templateId: string,
    newName: string,
    newDescription?: string,
    attributes?: Array<{ attributeId: string; value: string | null }>,
    groupId?: string | null,
    copyFirstSheetEmpty?: boolean
  ) => Promise<Template>
  updateTemplateOrder: (templateId: string, newOrder: number) => Promise<void>
  moveTemplateToGroup: (templateId: string, groupId: string | null) => Promise<void>
}

const TemplateContext = createContext<TemplateContextType | undefined>(
  undefined
)

export const TemplateProvider: React.FC<{ children: ReactNode }> = ({
  children,
}) => {
  const client = useQueryClient()

  const {
    data: templates = [],
    status: listStatus,
    error: errorList,
    refetch,
  } = useQuery<Template[], Error>({
    queryKey: ['templates'],
    queryFn: async () => {
      console.log('🔄 RELOADING TEMPLATES FROM API')
      const { templates: apiList } = await getTemplatesApi()
      console.log('📡 Raw API templates:', apiList.map(t => ({ id: t.id, name: t.name, order: t.order, group_id: t.group_id })))
      
      const processedTemplates = apiList.map(apiTemplateWithAttributesToTemplate)
      console.log('🔧 Processed templates:', processedTemplates.map(t => ({ id: t.id, name: t.name, order: t.order, group_id: t.group_id })))
      
      // Проверяем если есть шаблоны без order (null, undefined или 0) и автоматически их исправляем
      const templatesWithoutOrder = processedTemplates.filter(t => t.order == null || t.order === 0)
      if (templatesWithoutOrder.length > 0) {
        console.log('Found templates without valid order, fixing:', templatesWithoutOrder.map(t => ({ id: t.id, name: t.name, order: t.order })))
        
        // Группируем по группам и задаем order
        const templatesByGroup: Record<string, Template[]> = {}
        processedTemplates.forEach(template => {
          const groupKey = template.group_id || 'ungrouped'
          if (!templatesByGroup[groupKey]) templatesByGroup[groupKey] = []
          templatesByGroup[groupKey].push(template)
        })
        
        // Для каждой группы обновляем шаблоны без order
        for (const [groupKey, groupTemplates] of Object.entries(templatesByGroup)) {
          const templatesWithOrder = groupTemplates.filter(t => t.order != null && t.order > 0)
          const templatesWithoutOrderInGroup = groupTemplates.filter(t => t.order == null || t.order === 0)
          
          if (templatesWithoutOrderInGroup.length > 0) {
            const maxOrder = Math.max(0, ...templatesWithOrder.map(t => t.order ?? 0))
            
            // Обновляем каждый шаблон без order
            for (let i = 0; i < templatesWithoutOrderInGroup.length; i++) {
              const template = templatesWithoutOrderInGroup[i]
              const oldOrder = template.order
              const newOrder = maxOrder + (i + 1)
              
              try {
                // Обновляем в базе данных
                await patchTemplateApi(template.id, { 
                  name: template.name,
                  order: newOrder 
                })
                
                // Обновляем локально
                template.order = newOrder
                console.log(`Updated template ${template.id} order from ${oldOrder} to ${newOrder}`)
              } catch (error) {
                console.error(`Failed to update order for template ${template.id}:`, error)
              }
            }
          }
        }
      }
      
      console.log('✅ FINAL TEMPLATES RESULT:', processedTemplates.map(t => ({ id: t.id, name: t.name, order: t.order, group_id: t.group_id })))
      return processedTemplates
    },
  })

  const createMutation = useMutation({
    mutationFn: async ({
      template,
      attributes,
    }: {
      template: Omit<Template, 'id' | 'createdAt' | 'updatedAt'>
      attributes?: Array<{ attributeId: string; value: string | null }>
    }) => {
      const input = templateToCreateInput(template)
      if (attributes && attributes.length > 0) {
        input.attributes = attributes.map(attr => ({
          attribute_id: attr.attributeId,
          value: attr.value,
        }))
      }
      const { id } = await createTemplateApi(input)
      const { template: apiTpl } = await getTemplateApi(id)
      if (!apiTpl) throw new Error('Template not found')
      return apiTemplateToTemplate(apiTpl)
    },
    onSuccess: () => {
      client.invalidateQueries({ queryKey: ['templates'] })
    },
  })

  const updateMutation = useMutation({
    mutationFn: async ({
      template,
      attributes,
    }: {
      template: Template
      attributes?: Array<{ attributeId: string; value: string | null }>
    }) => {
      const input = templateToPatchInput(template)
      if (attributes) {
        input.attributes = attributes.map(attr => ({
          attribute_id: attr.attributeId,
          value: attr.value,
        }))
      }
      await patchTemplateApi(template.id, input)
      return template
    },
    onSuccess: updated => {
      client.setQueryData<Template[]>(
        ['templates'],
        old =>
          old?.map((t: Template) => (t.id === updated.id ? updated : t)) ?? []
      )
    },
  })

  const deleteMutation = useMutation({
    mutationFn: async (id: string) => {
      const result = await deleteTemplateApi(id)
      if (!result.success) {
        throw new Error('Не удалось удалить шаблон')
      }
      return id
    },
    onSuccess: id => {
      client.setQueryData<Template[]>(
        ['templates'],
        old => old?.filter((t: Template) => t.id !== id) ?? []
      )
    },
  })

  const copyMutation = useMutation({
    mutationFn: async ({
      templateId,
      newName,
      newDescription,
      attributes,
      groupId,
      copyFirstSheetEmpty,
    }: {
      templateId: string
      newName: string
      newDescription?: string
      attributes?: Array<{ attributeId: string; value: string | null }>
      groupId?: string | null
      copyFirstSheetEmpty?: boolean
    }) => {
      const input: CopyTemplateInput = {
        template_id: templateId,
        new_name: newName,
        new_description: newDescription || null,
        new_attributes:
          attributes?.map(attr => ({
            attribute_id: attr.attributeId,
            value: attr.value,
          })) || null,
        group_id: groupId,
        copy_first_sheet_empty: copyFirstSheetEmpty,
      }
      const { new_template_id } = await copyTemplateApi(input)
      const { template: apiTpl } = await getTemplateApi(new_template_id)
      if (!apiTpl) throw new Error('Copied template not found')
      return apiTemplateToTemplate(apiTpl)
    },
    onSuccess: () => {
      client.invalidateQueries({ queryKey: ['templates'] })
    },
  })

  // Мутация для обновления порядка шаблона
  const updateOrderMutation = useMutation({
    mutationFn: async ({ templateId, newOrder }: { templateId: string; newOrder: number }) => {
      const template = templates.find(t => t.id === templateId)
      if (!template) throw new Error('Template not found')
      
      console.log('🔄 Updating template order:', { templateId, newOrder, template: { id: template.id, name: template.name, currentOrder: template.order } })
      
      // Обновляем только порядок, но включаем обязательные поля
      const patchInput: PatchTemplateInput = { 
        name: template.name, // Включаем name как обязательное поле
        order: newOrder
      }
      
      console.log('📤 Sending to API:', patchInput)
      
      try {
        const result = await patchTemplateApi(templateId, patchInput)
        console.log('Order update successful:', result)
        return result
      } catch (error) {
        console.error('Order update failed:', error)
        throw error
      }
    },
    onSuccess: () => {
      client.invalidateQueries({ queryKey: ['templates'] })
    },
    onError: (error) => {
      console.error('Update order mutation error:', error)
    },
  })

  // Мутация для перемещения шаблона в другую группу
  const moveToGroupMutation = useMutation({
    mutationFn: async ({ templateId, groupId }: { templateId: string; groupId: string | null }) => {
      const template = templates.find(t => t.id === templateId)
      if (!template) throw new Error('Template not found')
      
      console.log('Moving template to group:', { templateId, groupId, template })
      
      // Если groupId равен null, отправляем "ungroup" для удаления из группы
      const patchInput: PatchTemplateInput = { 
        name: template.name, // Включаем name как обязательное поле
        group_id: groupId === null ? "ungroup" : groupId 
      }
      
      try {
        const result = await patchTemplateApi(templateId, patchInput)
        console.log('Group move successful:', result)
        return result
      } catch (error) {
        console.error('Group move failed:', error)
        throw error
      }
    },
    onSuccess: () => {
      client.invalidateQueries({ queryKey: ['templates'] })
    },
    onError: (error) => {
      console.error('Move to group mutation error:', error)
    },
  })

  const value = useMemo(
    () => ({
      templates,
      isLoading:
        listStatus === 'pending' ||
        createMutation.status === 'pending' ||
        updateMutation.status === 'pending' ||
        deleteMutation.status === 'pending' ||
        copyMutation.status === 'pending' ||
        updateOrderMutation.status === 'pending' ||
        moveToGroupMutation.status === 'pending',
      error:
        (errorList as Error) ||
        (createMutation.error as Error) ||
        (updateMutation.error as Error) ||
        (deleteMutation.error as Error) ||
        (copyMutation.error as Error) ||
        (updateOrderMutation.error as Error) ||
        (moveToGroupMutation.error as Error) ||
        null,
      refetchTemplates: refetch,
      addTemplate: async (
        template: Omit<Template, 'id' | 'createdAt' | 'updatedAt'>,
        attributes?: Array<{ attributeId: string; value: string | null }>
      ) =>
        createMutation.mutateAsync({
          template,
          attributes,
        }),
      updateTemplate: async (
        template: Template,
        attributes?: Array<{ attributeId: string; value: string | null }>
      ) =>
        updateMutation.mutateAsync({
          template,
          attributes,
        }),
      deleteTemplate: deleteMutation.mutateAsync,
      copyTemplate: async (
        templateId: string,
        newName: string,
        newDescription?: string,
        attributes?: Array<{ attributeId: string; value: string | null }>,
        groupId?: string | null,
        copyFirstSheetEmpty?: boolean
      ) =>
        copyMutation.mutateAsync({
          templateId,
          newName,
          newDescription,
          attributes,
          groupId,
          copyFirstSheetEmpty,
        }),
      updateTemplateOrder: async (templateId: string, newOrder: number) => {
        await updateOrderMutation.mutateAsync({ templateId, newOrder })
      },
      moveTemplateToGroup: async (templateId: string, groupId: string | null) => {
        await moveToGroupMutation.mutateAsync({ templateId, groupId })
      },
    }),
    [
      templates,
      listStatus,
      errorList,
      createMutation.status,
      createMutation.error,
      updateMutation.status,
      updateMutation.error,
      deleteMutation.status,
      deleteMutation.error,
      copyMutation.status,
      copyMutation.error,
      updateOrderMutation.status,
      updateOrderMutation.error,
      moveToGroupMutation.status,
      moveToGroupMutation.error,
      refetch,
      createMutation.mutateAsync,
      updateMutation.mutateAsync,
      deleteMutation.mutateAsync,
      copyMutation.mutateAsync,
      updateOrderMutation.mutateAsync,
      moveToGroupMutation.mutateAsync,
    ]
  )

  return (
    <TemplateContext.Provider value={value}>
      {children}
    </TemplateContext.Provider>
  )
}

export const useTemplateContext = (): TemplateContextType => {
  const ctx = useContext(TemplateContext)
  if (!ctx)
    throw new Error('useTemplateContext must be used within TemplateProvider')
  return ctx
}

export default TemplateProvider
