import Container from '@/components/shared/Container'
import { Notification, toast } from '@/components/ui'
import { DX_CLASSNAMES } from '@/constants/app.constant'
import {
  DbTypeEnum,
  GridDto,
  ListFormCustomizationTypeEnum,
  PlatformEditorTypes,
  UiLookupDataSourceTypeEnum,
} from '@/proxy/form/models'
import {
  getListFormCustomization,
  postListFormCustomization,
} from '@/services/list-form-customization.service'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { usePermission } from '@/utils/hooks/usePermission'
import { usePWA } from '@/utils/hooks/usePWA'
import CardViewDx, {
  CardViewRef,
  Column,
  ColumnChooser,
  Editing,
  HeaderFilter,
  SearchPanel,
  Sorting,
  Paging,
  Pager,
  Toolbar,
  ToolbarItem,
  Selection,
  FilterPanel,
} from 'devextreme-react/card-view'
import type {
  CardInsertingEvent,
  CardUpdatingEvent,
  EditingStartEvent,
  InitNewCardEvent,
  SelectionChangedEvent,
} from 'devextreme/ui/card_view'
import type { DataErrorOccurredInfo } from 'devextreme/common/grids'
import type { EventInfo } from 'devextreme/events'
import { EditingFormItemDto } from '@/proxy/form/models'
import { captionize } from 'devextreme/core/utils/inflector'
import CustomStore from 'devextreme/data/custom_store'
import DataSource from 'devextreme/data/data_source'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { Helmet } from 'react-helmet'
import { RowMode } from '../form/types'
import { GridColumnData } from './GridColumnData'
import {
  addCss,
  addJs,
  autoNumber,
  extractSearchParamsFields,
  GridExtraFilterState,
  setFormEditingExtraItemValues,
  setGridPanelColor,
} from './Utils'
import WidgetGroup from '@/components/ui/Widget/WidgetGroup'
import { GridExtraFilterToolbar } from './GridExtraFilterToolbar'
import { getList } from '@/services/form.service'
import { layoutTypes } from '../admin/listForm/edit/types'
import { useListFormCustomDataSource } from './useListFormCustomDataSource'
import { useListFormColumns } from './useListFormColumns'
import { Loading } from '@/components/shared'
import { useStoreState } from '@/store'
import { ROUTES_ENUM } from '@/routes/route.constant'
import { dynamicFetch } from '@/services/form.service'

interface CardViewProps {
  listFormCode: string
  searchParams?: URLSearchParams
  isSubForm?: boolean
  level?: number
  refreshData?: () => Promise<void>
  gridDto?: GridDto
  refreshGridDto?: () => Promise<void>
}

const statedGridPanelColor = 'rgba(50, 200, 200, 0.5)'

// Lookup cache (module scope)
const __lookupCache = new Map<string, Promise<any[]>>()

const cachedLoader = (key: string, loader: () => Promise<any[]>) => {
  if (__lookupCache.has(key)) return __lookupCache.get(key)!
  const p = Promise.resolve()
    .then(() => loader())
    .then((res) => res ?? [])
    .catch((err) => {
      __lookupCache.delete(key)
      throw err
    })
  __lookupCache.set(key, p)
  return p
}

const CardView = (props: CardViewProps) => {
  const { listFormCode, searchParams, isSubForm, gridDto: extGridDto, refreshGridDto } = props
  const { translate } = useLocalization()
  const { checkPermission } = usePermission()
  const isPwaMode = usePWA()
  const config = useStoreState((state) => state.abpConfig.config)

  const cardViewRef = useRef<CardViewRef<any, any>>(null)
  const refListFormCode = useRef('')
  const widgetGroupRef = useRef<HTMLDivElement>(null)

  const [columnData, setColumnData] = useState<GridColumnData[]>()
  const [formData, setFormData] = useState<any>()
  const [mode, setMode] = useState<RowMode>('view')
  const [extraFilters, setExtraFilters] = useState<GridExtraFilterState[]>([])
  const [gridDto, setGridDto] = useState<GridDto>()
  const [isPopupFullScreen, setIsPopupFullScreen] = useState(false)
  const [widgetGroupHeight, setWidgetGroupHeight] = useState(0)
  const [cardsPerRow, setCardsPerRow] = useState<number>(0)
  const [pageSize, setPageSize] = useState<number>(20)
  const [lookupItemsCache, setLookupItemsCache] = useState<Map<string, any[]>>(new Map())

  const defaultSearchParams = useRef<string | null>(null)

  useEffect(() => {
    const initializeCardView = async () => {
      const response = await getList({ listFormCode })
      setGridDto(response.data)
    }

    if (extGridDto === undefined) {
      initializeCardView()
    } else {
      setGridDto(extGridDto)
    }
  }, [listFormCode, extGridDto])

  useEffect(() => {
    if (!defaultSearchParams.current) {
      defaultSearchParams.current = searchParams?.get('filter') ?? null
    }
  }, [searchParams])

  // Clear lookup cache when listFormCode changes
  useEffect(() => {
    __lookupCache.clear()
  }, [listFormCode])

  const layout = layoutTypes.cardView

  const { createSelectDataSource } = useListFormCustomDataSource({ gridRef: cardViewRef as any })
  const { getBandedColumns } = useListFormColumns({
    gridDto,
    listFormCode,
    isSubForm,
    gridRef: cardViewRef as any,
  })

  // Lookup data source helpers
  const createLookupStaticDataSource = useCallback(
    (load: () => any, filter: any = null, key: any = 'static', sort: any = 'name') =>
      new DataSource({
        store: new CustomStore({
          key,
          loadMode: 'raw',
          load: async () => {
            return cachedLoader(`static:${key}`, () => Promise.resolve(load()))
          },
        }),
        paginate: false,
        sort,
        filter,
      }),
    [],
  )

  const createLookupQueryDataSource = useCallback(
    (listFormCode?: string, listFormFieldName?: string, filters?: any[]) => {
      return new DataSource({
        store: new CustomStore({
          loadMode: 'raw',
          load: async () => {
            try {
              const cacheKey = `query:${listFormCode}:${listFormFieldName}:${JSON.stringify(filters ?? null)}`
              return cachedLoader(cacheKey, async () => {
                const response = await dynamicFetch('list-form-select/lookup', 'POST', null, {
                  listFormCode,
                  listFormFieldName,
                  filters,
                })

                return (response.data ?? []).map((a: any) => ({
                  key: a.Key,
                  name: a.Name,
                  group: a.Group,
                  ...a,
                }))
              })
            } catch (error: any) {
              return []
            }
          },
        }),
        paginate: false,
      })
    },
    [],
  )

  const createLookupApiDataSource = useCallback(
    (listFormCode?: string, lookupQuery?: string, filters?: any[], keyName?: string) => {
      return new DataSource({
        store: new CustomStore({
          key: keyName,
          loadMode: 'raw',
          load: async () => {
            if (!lookupQuery) return []

            const [method, url, body, keySelector, nameSelector, groupSelector] =
              lookupQuery.split(';')

            let resolvedBody = body
            if (filters?.length) {
              for (let i = 0; i < filters.length; i++) {
                resolvedBody = resolvedBody.replace(
                  new RegExp(`@param${i}`, 'g'),
                  String(filters[i]),
                )
              }
            }

            try {
              const cacheKey = `api:${lookupQuery}:${JSON.stringify(filters ?? null)}`
              return cachedLoader(cacheKey, async () => {
                const response = await dynamicFetch(url, method, null, resolvedBody)
                let { data } = response
                if (!data) return []
                if (!Array.isArray(data)) data = [data]
                return data.map((a: any) => ({
                  key: eval(keySelector),
                  name: eval(nameSelector),
                  group: eval(groupSelector),
                  ...a,
                }))
              })
            } catch {
              return []
            }
          },
        }),
        paginate: false,
      })
    },
    [],
  )

  const lookupDataSource = useCallback(
    (options: any, colData: any) => {
      const { lookupDto } = colData
      const filters: any[] = []

      if (lookupDto.cascadeParentFields) {
        if (lookupDto.dataSourceType === UiLookupDataSourceTypeEnum.StaticData) {
          filters.push([
            lookupDto?.cascadeRelationField,
            lookupDto?.cascadeFilterOperator,
            options?.data?.[lookupDto?.cascadeParentField],
          ])
        } else {
          const data = options?.data ?? options
          for (const cascadeParentField of lookupDto.cascadeParentFields.split(',')) {
            filters.push(data?.[cascadeParentField])
          }
        }
      }

      if (lookupDto.dataSourceType === UiLookupDataSourceTypeEnum.StaticData) {
        return createLookupStaticDataSource(
          () => JSON.parse(lookupDto?.lookupQuery),
          filters.length ? filters : null,
          `static:${listFormCode}:${colData.fieldName}`,
        )
      } else if (lookupDto.dataSourceType === UiLookupDataSourceTypeEnum.Query) {
        return createLookupQueryDataSource(listFormCode, colData.fieldName, filters)
      } else if (lookupDto.dataSourceType === UiLookupDataSourceTypeEnum.WebService) {
        return createLookupApiDataSource(
          listFormCode,
          lookupDto?.lookupQuery,
          filters,
          colData.lookupDto?.valueExpr?.toLowerCase(),
        )
      }
      return { store: [] }
    },
    [
      listFormCode,
      createLookupStaticDataSource,
      createLookupQueryDataSource,
      createLookupApiDataSource,
    ],
  )

  function refreshData() {
    // Cache'i temizle
    if (typeof (window as any).__clearCardViewCache === 'function') {
      ;(window as any).__clearCardViewCache()
    }

    const instance = cardViewRef.current?.instance()
    if (instance) {
      instance.getDataSource()?.reload()
    }
  }

  // CardView specific events
  function onSelectionChanged(data: SelectionChangedEvent<any, any>) {
    const grdOpt = gridDto?.gridOptions
    const cardView = cardViewRef.current?.instance()
    if (!grdOpt || !cardView) {
      return
    }

    if (data.selectedCardsData?.length) {
      setFormData(data.selectedCardsData[0])
    }
  }

  function onInitNewCard(e: InitNewCardEvent<any>) {
    if (!gridDto?.columnFormats) {
      return
    }

    setMode('new')
    setIsPopupFullScreen(gridDto?.gridOptions.editingOptionDto?.popup?.fullScreen ?? false)

    for (const colFormat of gridDto?.columnFormats) {
      if (!colFormat.fieldName) {
        continue
      }

      // Grid'den gelen columnFormat'ları kullanarak default değerleri set et
      if (colFormat.defaultValue != null) {
        const defaultValStr = String(colFormat.defaultValue)
        if (defaultValStr === '@AUTONUMBER') {
          e.data[colFormat.fieldName] = autoNumber()
        } else {
          e.data[colFormat.fieldName] = colFormat.defaultValue
        }
      }

      // ExtraFilters içerisinde ilgili Field varsa, default değerleri set etme
      if (extraFilters.some((f) => f.fieldName === colFormat.fieldName)) {
        continue
      }

      // URL'den veya Component Prop'dan gelen parametreleri set et
      const defaultValue = searchParams?.get(colFormat.fieldName)
      if (defaultValue) {
        e.data[colFormat.fieldName] = defaultValue
      }
    }
  }

  function onCardInserting(e: CardInsertingEvent<any>) {
    e.data = setFormEditingExtraItemValues(e.data)
  }

  function onCardUpdating(e: CardUpdatingEvent<any, any>) {
    if (gridDto?.gridOptions.editingOptionDto?.sendOnlyChangedFormValuesUpdate) {
      e.newData = {
        ...e.newData,
        [gridDto?.gridOptions.keyFieldName!]: e.oldData[gridDto?.gridOptions.keyFieldName!],
      }
    } else {
      e.newData = {
        ...e.oldData,
        ...e.newData,
        [gridDto?.gridOptions.keyFieldName!]: e.oldData[gridDto?.gridOptions.keyFieldName!],
      }
    }

    if (gridDto?.gridOptions.keyFieldName) {
      e.newData = setFormEditingExtraItemValues(e.newData)
    }
  }

  function onEditingStart(e: EditingStartEvent<any, any>) {
    setMode('edit')
    setIsPopupFullScreen(gridDto?.gridOptions.editingOptionDto?.popup?.fullScreen ?? false)
  }

  function onDataErrorOccurred(e: EventInfo<any> & DataErrorOccurredInfo) {
    toast.push(
      <Notification type="danger" duration={5000}>
        {(e.error as any)?.message || 'An error occurred'}
      </Notification>,
      {
        placement: 'top-end',
      },
    )
  }

  const customSaveState = useCallback(
    (state: any) => {
      return postListFormCustomization({
        listFormCode: listFormCode,
        customizationType: ListFormCustomizationTypeEnum.GridState,
        filterName: `cardview-state`,
        customizationData: JSON.stringify(state),
      }).then(() => {
        setGridPanelColor(statedGridPanelColor)
      })
    },
    [listFormCode],
  )

  const customLoadState = useCallback(() => {
    return getListFormCustomization(
      listFormCode,
      ListFormCustomizationTypeEnum.GridState,
      `cardview-state`,
    ).then((response: any) => {
      setGridPanelColor(statedGridPanelColor)
      if (response.data?.length > 0) {
        return JSON.parse(response.data[0].customizationData)
      }
    })
  }, [listFormCode])

  useEffect(() => {
    if (cardViewRef?.current) {
      const instance = cardViewRef?.current?.instance()
      if (instance) {
        instance.option('dataSource', undefined)
      }
    }

    if (refListFormCode.current !== listFormCode) {
      setColumnData(undefined)
    }
  }, [listFormCode])

  useEffect(() => {
    if (!gridDto) {
      return
    }

    // Set js and css
    const grdOpt = gridDto.gridOptions
    if (grdOpt.customJsSources.length) {
      for (const js of grdOpt.customJsSources) {
        addJs(js)
      }
    }
    if (grdOpt.customStyleSources.length) {
      for (const css of grdOpt.customStyleSources) {
        addCss(css)
      }
    }

    if (gridDto?.gridOptions.extraFilterDto) {
      const extras = gridDto.gridOptions.extraFilterDto.map((f) => ({
        fieldName: f.fieldName,
        caption: f.caption,
        operator: f.operator || '=',
        value: f.defaultValue || '',
        controlType: f.controlType,
      }))
      // Sadece ilk yüklemede extraFilters'ı set et, her gridDto değişiminde değil
      setExtraFilters((prev) => {
        if (prev.length === 0) return extras
        return prev
      })
    }

    if (gridDto?.gridOptions.editingOptionDto?.popup) {
      setIsPopupFullScreen(gridDto.gridOptions.editingOptionDto.popup.fullScreen)
    }

    // cardsPerRow başlangıç değeri - localStorage'dan oku
    const storageKey = `cardview-cardsPerRow-${listFormCode}`
    const savedCardsPerRow = localStorage.getItem(storageKey)

    if (savedCardsPerRow !== null) {
      setCardsPerRow(parseInt(savedCardsPerRow, 10))
    } else if (gridDto?.gridOptions.layoutDto?.cardLayoutColumn) {
      setCardsPerRow(gridDto.gridOptions.layoutDto.cardLayoutColumn)
    }

    // pageSize başlangıç değeri
    if (gridDto?.gridOptions.pageSize) {
      setPageSize(gridDto.gridOptions.pageSize)
    }
  }, [gridDto, listFormCode])

  // Lookup DataSource'ları bir kere oluştur ve cache'le
  const lookupDataSourcesRef = useRef<Map<string, any>>(new Map())

  // gridDto değiştiğinde lookup cache'i temizle
  useEffect(() => {
    lookupDataSourcesRef.current.clear()
  }, [gridDto, listFormCode])

  // Build columns with lookup support - sadece gridDto değiştiğinde
  const columnsWithLookup = useMemo(() => {
    if (!gridDto || !config) return []

    const cols = getBandedColumns()
    if (!cols) return []

    return cols.map((col) => {
      const colData = gridDto.columnFormats.find((c) => c.fieldName === col.dataField)
      if (!colData) return col

      // Type assertion for extended column properties
      const extCol = col as any

      // Form items için editorType ve editorOptions ayarla
      const gridFormItem = gridDto.gridOptions.editingFormDto
        ?.flatMap((f) => f.items)
        .find((i) => i?.dataField === col.dataField)

      // Lookup desteği ekle - dataSourceType > 0 olmalı (0 = None)
      if (colData.lookupDto?.dataSourceType && colData.lookupDto.dataSourceType > 0) {
        // Cache'den al veya oluştur
        const cacheKey = `${colData.fieldName}`
        let lookupDs = lookupDataSourcesRef.current.get(cacheKey)

        if (!lookupDs) {
          lookupDs = lookupDataSource(null, colData)
          lookupDataSourcesRef.current.set(cacheKey, lookupDs)
        }

        // NOT: Lookup için CardView'da editorType ve editorOptions KULLANMA
        // DevExpress bunları görünce otomatik lookup resolution yapıp çift görünmeye sebep oluyor
        // Sadece fieldValueRender ile lookup gösterimi yapılacak
        // Edit popup'ta form item için lookup ayarları yapılacak

        // Lookup olduğunu işaretle (renderColumns'da kullanılacak)
        ;(col as any).isLookup = true
        ;(col as any).lookupInfo = {
          valueExpr: colData.lookupDto?.valueExpr?.toLowerCase() || 'key',
          displayExpr: colData.lookupDto?.displayExpr?.toLowerCase() || 'name',
        }
      }

      // Form item ayarları
      if (gridFormItem) {
        const editorOptions: any = {}

        // Parse editorOptions from JSON
        if (gridFormItem.editorOptions) {
          try {
            Object.assign(editorOptions, JSON.parse(gridFormItem.editorOptions))
          } catch {}
        }

        // EditorType belirleme (SchedulerView pattern'i)
        let editorType: any = gridFormItem.editorType2 || gridFormItem.editorType
        if (gridFormItem.editorType2 === PlatformEditorTypes.dxGridBox) {
          editorType = 'dxDropDownBox'
        } else if (gridFormItem.editorType2 === PlatformEditorTypes.dxTagBox) {
          editorType = 'dxTagBox'
        } else if (gridFormItem.editorType2) {
          editorType = gridFormItem.editorType2
        }

        // Lookup için dataSource ve valueExpr/displayExpr ekle - dataSourceType > 0 olmalı
        if (colData.lookupDto?.dataSourceType && colData.lookupDto.dataSourceType > 0) {
          // Cache'den al
          const cacheKey = `${colData.fieldName}`
          const lookupDs = lookupDataSourcesRef.current.get(cacheKey)

          if (lookupDs) {
            editorOptions.dataSource = lookupDs
            editorOptions.valueExpr = colData.lookupDto?.valueExpr?.toLowerCase() || 'key'
            editorOptions.displayExpr = colData.lookupDto?.displayExpr?.toLowerCase() || 'name'
            editorOptions.searchEnabled = true
            editorOptions.showClearButton = true
          }

          // Lookup varsa SelectBox kullan (eğer başka bir tip belirtilmediyse)
          if (!editorType || editorType === 'dxTextBox') {
            editorType = 'dxSelectBox'
          }
        }

        // Date/DateTime alanları için özel ayarlar
        if (colData.sourceDbType === DbTypeEnum.Date) {
          editorType = 'dxDateBox'
          editorOptions.type = 'date'
          editorOptions.dateSerializationFormat = 'yyyy-MM-dd'
          editorOptions.displayFormat = 'shortDate'
        } else if (
          colData.sourceDbType === DbTypeEnum.DateTime ||
          colData.sourceDbType === DbTypeEnum.DateTime2 ||
          colData.sourceDbType === DbTypeEnum.DateTimeOffset
        ) {
          editorType = 'dxDateBox'
          editorOptions.type = 'datetime'
          editorOptions.dateSerializationFormat = 'yyyy-MM-ddTHH:mm:ss'
          editorOptions.displayFormat = 'shortDateShortTime'
        }

        col.formItem = {
          ...col.formItem,
          colSpan: gridFormItem.colSpan,
        }

        if (editorType) {
          extCol.editorType = editorType
        }

        col.editorOptions = {
          ...col.editorOptions,
          ...editorOptions,
        }
      }

      return col
    })
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [gridDto, config]) // getBandedColumns ve lookupDataSource çıkarıldı - sonsuz döngüyü önlemek için

  // DataSource oluştur - sadece gridDto ve listFormCode değiştiğinde (useMemo ile cache'le)
  const cardViewDataSource = useMemo(() => {
    if (!gridDto) return null

    const cols = getBandedColumns()
    if (!cols || cols.length === 0) return null

    const baseStore = createSelectDataSource(
      gridDto.gridOptions,
      listFormCode,
      searchParams,
      layoutTypes.cardView,
      cols,
    )

    // CardView için sadece 1 select çağrısı yapacak wrapper
    let cachedData: any[] | null = null
    let cachedTotalCount: number = 0
    let isLoading = false
    const keyExpr = gridDto.gridOptions.keyFieldName

    const clearCache = () => {
      cachedData = null
      cachedTotalCount = 0
      isLoading = false
    }

    // Cache temizleme fonksiyonunu dışarıya expose et
    ;(window as any).__clearCardViewCache = clearCache

    const optimizedStore: any = new CustomStore({
      key: keyExpr,
      load: async (loadOptions: any) => {
        // Zaten yüklenmişse cache'den dön
        if (cachedData !== null && !isLoading) {
          return {
            data: cachedData,
            totalCount: cachedTotalCount,
          }
        }

        // Yükleme devam ediyorsa bekle
        if (isLoading) {
          await new Promise((resolve) => setTimeout(resolve, 100))
          if (cachedData !== null) {
            return {
              data: cachedData,
              totalCount: cachedTotalCount,
            }
          }
        }

        isLoading = true
        try {
          const result = await baseStore.load(loadOptions)
          cachedData = result?.data || []
          cachedTotalCount = result?.totalCount || 0
          return result
        } finally {
          isLoading = false
        }
      },
      byKey: async (key: any) => {
        // Cache'de ara
        if (cachedData && keyExpr) {
          const item = cachedData.find((row: any) => row?.[keyExpr] === key)
          if (item) return item
        }

        // Bulamazsa server'a git
        return baseStore.byKey(key)
      },
      insert: async (values: any) => {
        const result = await baseStore.insert(values)
        clearCache()
        return result
      },
      update: async (key: any, values: any) => {
        const result = await baseStore.update(key, values)
        clearCache()
        return result
      },
      remove: async (key: any) => {
        const result = await baseStore.remove(key)
        clearCache()
        return result
      },
    })

    // DataSource içine sar
    return new DataSource({
      store: optimizedStore,
      reshapeOnPush: true,
      paginate: true,
      pageSize: pageSize,
    })
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [gridDto, listFormCode])

  // extraFilters değişikliğini izlemek için ref
  const extraFiltersInitialized = useRef(false)

  useEffect(() => {
    // İlk yüklemede reload yapma, sadece kullanıcı filtre değiştirdiğinde
    if (!extraFiltersInitialized.current) {
      extraFiltersInitialized.current = true
      return
    }

    const instance = cardViewRef.current?.instance()
    if (!instance) return

    const activeFilters = extraFilters.filter((f) => f.value)

    let base: any = null
    if (defaultSearchParams.current) {
      base = JSON.parse(defaultSearchParams.current)
    }

    const baseTriplets = extractSearchParamsFields(base)
    const extraTriplets = activeFilters.map(
      (f) => [f.fieldName, f.operator, f.value] as [string, string, any],
    )

    const merged = [...baseTriplets, ...extraTriplets].reduce(
      (acc, cur) => {
        const idx = acc.findIndex((a) => a[0] === cur[0] && a[1] === cur[1])
        if (idx >= 0) {
          acc[idx] = cur
        } else {
          acc.push(cur)
        }
        return acc
      },
      [] as [string, string, any][],
    )

    let filter: any = null
    if (merged.length === 1) {
      filter = merged[0]
    } else if (merged.length > 1) {
      filter = merged.reduce((acc, f, idx) => {
        if (idx === 0) return f
        return [acc, 'and', f]
      }, null as any)
    }

    if (filter) {
      instance?.option('filterValue', filter)
    } else {
      instance?.option('filterValue', undefined)
    }

    instance?.getDataSource()?.reload()
  }, [extraFilters])

  useEffect(() => {
    refListFormCode.current = listFormCode
  }, [listFormCode])

  // WidgetGroup yüksekliğini hesapla
  useEffect(() => {
    const calculateWidgetHeight = () => {
      if (widgetGroupRef.current) {
        const height = widgetGroupRef.current.offsetHeight
        setWidgetGroupHeight(height)
      }
    }

    calculateWidgetHeight()

    const resizeObserver = new ResizeObserver(calculateWidgetHeight)
    if (widgetGroupRef.current) {
      resizeObserver.observe(widgetGroupRef.current)
    }

    return () => {
      resizeObserver.disconnect()
    }
  }, [gridDto?.widgets])

  const settingButtonClick = useCallback(() => {
    window.open(
      ROUTES_ENUM.protected.saas.listFormManagement.edit.replace(':listFormCode', listFormCode),
      isPwaMode ? '_self' : '_blank',
    )
  }, [listFormCode, isPwaMode])

  const customizeLookupText = useCallback(
    (fieldName: string) => {
      return (cellInfo: any) => {
        const value = cellInfo.value
        if (!value) return ''

        const cacheKey = fieldName
        const items = lookupItemsCache.get(cacheKey)

        if (!items || items.length === 0) {
          return value
        }

        try {
          const colData = gridDto?.columnFormats.find((c) => c.fieldName === fieldName)
          const valueExpr = colData?.lookupDto?.valueExpr?.toLowerCase() || 'key'
          const displayExpr = colData?.lookupDto?.displayExpr?.toLowerCase() || 'name'

          const item = items.find((i: any) => i[valueExpr] === value)

          return item ? item[displayExpr] : value
        } catch {
          return value
        }
      }
    },
    [gridDto, lookupItemsCache],
  )

  // CardView column render from GridColumnData
  const renderColumns = () => {
    if (!columnsWithLookup || !Array.isArray(columnsWithLookup) || columnsWithLookup.length === 0) {
      return null
    }

    return columnsWithLookup
      .filter((col) => col.type !== 'buttons' && col.visible !== false)
      .map((col) => {
        const extCol = col as any
        const colData = gridDto?.columnFormats.find((c) => c.fieldName === col.dataField)

        // Column props
        const columnProps: any = {
          dataField: col.dataField,
          caption: col.caption ? translate('::' + col.caption) : captionize(col.dataField || ''),
          dataType: col.dataType,
          visible: col.visible,
          allowSorting: col.allowSorting,
          allowFiltering: col.allowFiltering,
          allowHeaderFiltering: col.allowHeaderFiltering,
          sortOrder: col.sortOrder,
          sortIndex: col.sortIndex,
          format: col.format,
          alignment: col.alignment,
          formItem: col.formItem,
        }

        // Lookup varsa customizeText kullan - fieldValueRender çift görünmeye sebep oluyor
        if (extCol.isLookup) {
          columnProps.customizeText = customizeLookupText(col.dataField!)
        } else {
          // Lookup değilse editorType ve editorOptions ekle
          if (extCol.editorType) {
            columnProps.editorType = extCol.editorType
          }
          if (col.editorOptions) {
            columnProps.editorOptions = col.editorOptions
          }

          // fieldValueRender - farklı veri tipleri için özel renderlar (lookup değilse)
          if (colData?.sourceDbType === DbTypeEnum.Date || col.dataType === 'date') {
            columnProps.customizeText = (cellInfo: any) => {
              if (!cellInfo.value) return '—'
              return new Date(cellInfo.value).toLocaleDateString()
            }
          } else if (
            colData?.sourceDbType === DbTypeEnum.DateTime ||
            colData?.sourceDbType === DbTypeEnum.DateTime2 ||
            colData?.sourceDbType === DbTypeEnum.DateTimeOffset ||
            col.dataType === 'datetime'
          ) {
            columnProps.customizeText = (cellInfo: any) => {
              if (!cellInfo.value) return '—'
              return new Date(cellInfo.value).toLocaleString()
            }
          }
        }

        // Boolean için customizeText kullan (fieldValueRender çift checkbox oluşturuyor)
        if (colData?.sourceDbType === DbTypeEnum.Boolean || col.dataType === 'boolean') {
          columnProps.customizeText = (cellInfo: any) => {
            return cellInfo.value
              ? translate('::App.Listforms.ImportManager.Yes')
              : translate('::App.Listforms.ImportManager.No')
          }
        }

        return <Column key={col.dataField} {...columnProps} />
      })
  }

  // Kolon sayısı değiştiğinde
  const onCardsPerRowChanged = useCallback(
    (value: number) => {
      setCardsPerRow(value)
      // localStorage'a kaydet
      const storageKey = `cardview-cardsPerRow-${listFormCode}`
      localStorage.setItem(storageKey, value.toString())
    },
    [listFormCode],
  )

  // Page size değiştiğinde
  const onPageSizeChanged = useCallback((newPageSize: number) => {
    setPageSize(newPageSize)
    const instance = cardViewRef.current?.instance()
    if (instance) {
      instance.pageSize(newPageSize)
    }
  }, [])

  // Toolbar items
  const toolbarItems = useMemo(() => {
    if (!gridDto) return []
    
    const items: any[] = [
      { name: 'addCardButton' },
      { name: 'searchPanel' },
      {
        location: 'after',
        widget: 'dxButtonGroup',
        options: {
          items: [
            { text: 'Auto', value: 0, hint: 'Otomatik' },
            { text: '1', value: 1, hint: '1 Kolon' },
            { text: '2', value: 2, hint: '2 Kolon' },
            { text: '3', value: 3, hint: '3 Kolon' },
            { text: '4', value: 4, hint: '4 Kolon' },
            { text: '5', value: 5, hint: '5 Kolon' },
          ],
          keyExpr: 'value',
          selectedItemKeys: [cardsPerRow || 0],
          selectionMode: 'single',
          stylingMode: 'outlined',
          onItemClick: (e: any) => {
            if (e.itemData) {
              onCardsPerRowChanged(e.itemData.value)
            }
          },
        },
      },
      {
        location: 'after',
        widget: 'dxButton',
        options: {
          icon: 'refresh',
          hint: translate('::Refresh'),
          stylingMode: 'text',
          onClick: () => refreshData(),
        },
      },
    ]

    // Column Chooser butonu için permission kontrolü
    if (checkPermission(gridDto?.gridOptions.permissionDto?.u)) {
      items.push({
        location: 'after',
        widget: 'dxButton',
        options: {
          icon: 'columnchooser',
          hint: translate('::ColumnChooser'),
          stylingMode: 'text',
          onClick: () => {
            const instance = cardViewRef.current?.instance()
            instance?.showColumnChooser()
          },
        },
      })
    }

    // Settings butonu için permission kontrolü
    if (checkPermission(gridDto?.gridOptions.permissionDto?.u)) {
      items.push({
        location: 'after',
        widget: 'dxButton',
        options: {
          icon: 'preferences',
          hint: translate('::ListForms.ListForm.Manage'),
          stylingMode: 'text',
          onClick: settingButtonClick,
        },
      })
    }

    return items
  }, [
    gridDto,
    cardsPerRow
  ])

  // Paging ayarları
  const pagingConfig = useMemo(
    () => ({
      enabled: gridDto?.gridOptions.pagerOptionDto?.visible !== false,
      pageSize: pageSize,
    }),
    [gridDto?.gridOptions.pagerOptionDto?.visible, pageSize],
  )

  // Pager ayarları
  const pagerConfig = useMemo(() => {
    const allowedSizes = gridDto?.gridOptions.pagerOptionDto?.allowedPageSizes
      ?.split(',')
      .map((s) => Number(s.trim()))
      .filter((n) => !isNaN(n) && n > 0) || [10, 20, 50, 100]

    return {
      visible: gridDto?.gridOptions.pagerOptionDto?.visible !== false,
      showPageSizeSelector: gridDto?.gridOptions.pagerOptionDto?.showPageSizeSelector !== false,
      showInfo: gridDto?.gridOptions.pagerOptionDto?.showInfo !== false,
      showNavigationButtons: gridDto?.gridOptions.pagerOptionDto?.showNavigationButtons !== false,
      allowedPageSizes: allowedSizes,
      displayMode: gridDto?.gridOptions.pagerOptionDto?.displayMode || 'full',
      infoText: gridDto?.gridOptions.pagerOptionDto?.infoText,
    }
  }, [gridDto?.gridOptions.pagerOptionDto])

  return (
    <>
      <div ref={widgetGroupRef}>
        <WidgetGroup widgetGroups={gridDto?.widgets ?? []} />
      </div>

      {gridDto?.gridOptions.extraFilterDto && gridDto?.gridOptions.extraFilterDto.length > 0 && (
        <GridExtraFilterToolbar
          filters={gridDto.gridOptions.extraFilterDto}
          extraFilters={extraFilters}
          setExtraFilters={setExtraFilters}
        />
      )}

      <Container className={DX_CLASSNAMES}>
        {!isSubForm && (
          <Helmet
            titleTemplate="%s | Erp Platform"
            title={translate('::' + gridDto?.gridOptions.title)}
            defaultTitle="Erp Platform"
          />
        )}

        {!gridDto && (
          <div className="p-4">
            <Loading loading>Loading CardView configuration...</Loading>
          </div>
        )}

        {gridDto && !cardViewDataSource && (
          <div className="p-4">
            <Loading loading>Loading data source...</Loading>
          </div>
        )}

        {gridDto && columnsWithLookup && Array.isArray(columnsWithLookup) && columnsWithLookup.length > 0 && cardViewDataSource && (
          <div className="p-1 bg-white dark:bg-neutral-800 dark:border-neutral-700">
            <CardViewDx
              ref={cardViewRef as any}
              key={`CardView-${listFormCode}`}
              id={'CardView-' + listFormCode}
              dataSource={cardViewDataSource}
              keyExpr={gridDto.gridOptions.keyFieldName}
              cardsPerRow={cardsPerRow || 'auto'}
              wordWrapEnabled={true}
              hoverStateEnabled={gridDto.gridOptions.columnOptionDto?.hoverStateEnabled}
              height={
                gridDto.gridOptions.height > 0
                  ? gridDto.gridOptions.height
                  : gridDto.gridOptions.fullHeight
                    ? `calc(100vh - ${170 + widgetGroupHeight}px)`
                    : undefined
              }
              remoteOperations={false}
              onSelectionChanged={onSelectionChanged as any}
              onInitNewCard={onInitNewCard as any}
              onCardInserting={onCardInserting as any}
              onCardUpdating={onCardUpdating as any}
              onEditingStart={onEditingStart as any}
              onDataErrorOccurred={onDataErrorOccurred as any}
              onEditCanceled={() => {
                setMode('view')
                setIsPopupFullScreen(false)
              }}
              onCardInserted={() => {
                setMode('view')
                setIsPopupFullScreen(false)
                // Küçük bir gecikme ile reload - server transaction commit bekle
                setTimeout(() => {
                  refreshData()
                  props.refreshData?.()
                }, 100)
              }}
              onCardUpdated={() => {
                setMode('view')
                setIsPopupFullScreen(false)
                // Küçük bir gecikme ile reload - server transaction commit bekle
                setTimeout(() => {
                  refreshData()
                  props.refreshData?.()
                }, 100)
              }}
              onCardRemoved={() => {
                // Küçük bir gecikme ile reload - server transaction commit bekle
                setTimeout(() => {
                  refreshData()
                  props.refreshData?.()
                }, 100)
              }}
              onOptionChanged={(e: any) => {
                if (e.name === 'paging.pageSize' && e.value !== pageSize) {
                  setPageSize(e.value)
                }
              }}
              onContentReady={() => {
                // Lookup DataSource'ları yükle ve state'e cache'le (sadece ilk yüklemede)
                if (lookupItemsCache.size === 0 && lookupDataSourcesRef.current.size > 0) {
                  const lookupPromises: Array<Promise<{ key: string; items: any[] }>> = []

                  lookupDataSourcesRef.current.forEach((ds, key) => {
                    if (ds && typeof ds.load === 'function') {
                      lookupPromises.push(
                        ds.load().then(() => ({
                          key,
                          items: ds.items() || [],
                        })),
                      )
                    }
                  })

                  if (lookupPromises.length > 0) {
                    Promise.all(lookupPromises)
                      .then((results) => {
                        const newCache = new Map<string, any[]>()
                        results.forEach(({ key, items }) => {
                          newCache.set(key, items)
                        })
                        setLookupItemsCache(newCache)

                        const instance = cardViewRef.current?.instance()
                        if (instance) {
                          instance.repaint()
                        }
                      })
                      .catch(() => {
                        // Hata durumunda sessizce devam et
                      })
                  }
                }
              }}
            >
              {/* Toolbar */}
              <Toolbar items={toolbarItems} />

              {/* Selection */}
              <Selection
                mode={gridDto.gridOptions.selectionDto?.mode}
                allowSelectAll={gridDto.gridOptions.selectionDto?.allowSelectAll}
                selectAllMode={gridDto.gridOptions.selectionDto?.selectAllMode}
                showCheckBoxesMode={gridDto.gridOptions.selectionDto?.showCheckBoxesMode}
              />

              {/* Sorting */}
              <Sorting mode={gridDto.gridOptions.sortMode} />

              {/* Header Filter */}
              <HeaderFilter
                visible={gridDto.gridOptions.headerFilterDto?.visible}
                allowSearch={gridDto.gridOptions.headerFilterDto?.allowSearch}
                height={gridDto.gridOptions.headerFilterDto?.height}
                searchTimeout={gridDto.gridOptions.headerFilterDto?.searchTimeout}
                width={gridDto.gridOptions.headerFilterDto?.width}
              />

              {/* Filter Panel */}
              <FilterPanel
                visible={gridDto.gridOptions.filterPanelDto?.visible}
                filterEnabled={gridDto.gridOptions.filterPanelDto?.filterEnabled}
              />

              {/* Search Panel */}
              <SearchPanel
                visible={gridDto.gridOptions.searchPanelDto?.visible}
                width={gridDto.gridOptions.searchPanelDto?.width}
              />

              {/* Column Chooser */}
              <ColumnChooser enabled={true} mode="select" />

              {/* Paging */}
              <Paging enabled={pagingConfig.enabled} defaultPageSize={pagingConfig.pageSize} />

              {/* Pager */}
              <Pager
                visible={pagerConfig.visible}
                showPageSizeSelector={pagerConfig.showPageSizeSelector}
                showInfo={pagerConfig.showInfo}
                showNavigationButtons={pagerConfig.showNavigationButtons}
                allowedPageSizes={pagerConfig.allowedPageSizes}
                displayMode={pagerConfig.displayMode as any}
                infoText={pagerConfig.infoText}
              />

              {/* Editing */}
              <Editing
                allowUpdating={
                  gridDto.gridOptions.editingOptionDto?.allowUpdating &&
                  checkPermission(gridDto.gridOptions.permissionDto?.u)
                }
                allowAdding={
                  gridDto.gridOptions.editingOptionDto?.allowAdding &&
                  checkPermission(gridDto.gridOptions.permissionDto?.c)
                }
                allowDeleting={
                  gridDto.gridOptions.editingOptionDto?.allowDeleting &&
                  checkPermission(gridDto.gridOptions.permissionDto?.d)
                }
                confirmDelete={gridDto.gridOptions.editingOptionDto?.confirmDelete}
                popup={{
                  animation: {},
                  title:
                    (mode === 'new' ? '✚ ' : '🖊️ ') +
                    translate('::' + gridDto.gridOptions.editingOptionDto?.popup?.title),
                  showTitle: gridDto.gridOptions.editingOptionDto?.popup?.showTitle,
                  width: isPopupFullScreen
                    ? '100%'
                    : gridDto.gridOptions.editingOptionDto?.popup?.width || 600,
                  height: isPopupFullScreen
                    ? '100%'
                    : gridDto.gridOptions.editingOptionDto?.popup?.height || 'auto',
                  fullScreen: isPopupFullScreen,
                  hideOnOutsideClick:
                    gridDto.gridOptions.editingOptionDto?.popup?.hideOnOutsideClick,
                  resizeEnabled: gridDto.gridOptions.editingOptionDto?.popup?.resizeEnabled,
                  toolbarItems: [
                    {
                      widget: 'dxButton',
                      toolbar: 'bottom',
                      location: 'after',
                      options: {
                        text: translate('::Save'),
                        type: 'default',
                        onClick: () => {
                          const cardView = cardViewRef.current?.instance()
                          if (cardView) {
                            // Form validasyonu yap
                            const editForm = (cardView as any).getController?.('validating')?.validate?.()
                            
                            // Eğer validate fonksiyonu yoksa direkt kaydet
                            if (!editForm) {
                              cardView.saveEditData()
                              return
                            }
                            
                            // Validasyon hatası varsa kaydetme
                            if (editForm && !editForm.brokenRules?.length) {
                              cardView.saveEditData()
                            }
                          }
                        },
                      },
                    },
                    {
                      widget: 'dxButton',
                      toolbar: 'bottom',
                      location: 'after',
                      options: {
                        text: translate('::Cancel'),
                        onClick: () => {
                          const cardView = cardViewRef.current?.instance()
                          cardView?.cancelEditData()
                        },
                      },
                    },
                    {
                      widget: 'dxButton',
                      toolbar: 'top',
                      location: 'after',
                      options: {
                        icon: isPopupFullScreen ? 'collapse' : 'fullscreen',
                        hint: isPopupFullScreen
                          ? translate('::Normal Boyut')
                          : translate('::Tam Ekran'),
                        stylingMode: 'text',
                        onClick: () => setIsPopupFullScreen(!isPopupFullScreen),
                      },
                    },
                  ],
                }}
                form={{
                  colCount: gridDto.gridOptions.editingFormDto?.[0]?.colCount || 2,
                  showValidationSummary: true,
                  items:
                    gridDto.gridOptions.editingFormDto?.length > 0
                      ? (() => {
                          const sortedFormDto = gridDto.gridOptions.editingFormDto
                            .slice()
                            .sort((a: any, b: any) => (a.order >= b.order ? 1 : -1))

                          const tabbedItems = sortedFormDto.filter(
                            (e: any) => e.itemType === 'tabbed',
                          )
                          const result: any[] = []

                          const mapFormItem = (i: EditingFormItemDto) => {
                            let editorOptions: any = {}
                            try {
                              if (i.editorOptions) {
                                editorOptions = JSON.parse(i.editorOptions)
                              }
                            } catch {}

                            const fieldName = i.dataField.split(':')[0]
                            const listFormField = gridDto.columnFormats.find(
                              (x: any) => x.fieldName === fieldName,
                            )

                            if (listFormField?.sourceDbType === DbTypeEnum.Date) {
                              editorOptions = {
                                ...{
                                  type: 'date',
                                  dateSerializationFormat: 'yyyy-MM-dd',
                                  displayFormat: 'shortDate',
                                },
                                ...editorOptions,
                              }
                            } else if (
                              listFormField?.sourceDbType === DbTypeEnum.DateTime ||
                              listFormField?.sourceDbType === DbTypeEnum.DateTime2 ||
                              listFormField?.sourceDbType === DbTypeEnum.DateTimeOffset
                            ) {
                              editorOptions = {
                                ...{
                                  type: 'datetime',
                                  dateSerializationFormat: 'yyyy-MM-ddTHH:mm:ss',
                                  displayFormat: 'shortDateShortTime',
                                },
                                ...editorOptions,
                              }
                            }

                            // Set defaultValue for @AUTONUMBER fields
                            if (
                              typeof listFormField?.defaultValue === 'string' &&
                              listFormField?.defaultValue === '@AUTONUMBER' &&
                              mode === 'new'
                            ) {
                              editorOptions = {
                                ...editorOptions,
                                value: autoNumber(),
                              }
                            }

                            // EditorType belirleme
                            let editorType: any = i.editorType2 || i.editorType
                            if (i.editorType2 === PlatformEditorTypes.dxGridBox) {
                              editorType = 'dxDropDownBox'
                            } else if (i.editorType2) {
                              editorType = i.editorType2
                            }

                            // Lookup DataSource oluştur
                            if (
                              listFormField?.lookupDto &&
                              listFormField.lookupDto.dataSourceType > 0
                            ) {
                              const cacheKey = `${listFormField.fieldName}`
                              let lookupDs = lookupDataSourcesRef.current.get(cacheKey)

                              if (!lookupDs) {
                                lookupDs = lookupDataSource(null, listFormField)
                                lookupDataSourcesRef.current.set(cacheKey, lookupDs)
                              }

                              editorOptions.dataSource = lookupDs
                              editorOptions.valueExpr =
                                listFormField.lookupDto.valueExpr?.toLowerCase() || 'key'
                              editorOptions.displayExpr =
                                listFormField.lookupDto.displayExpr?.toLowerCase() || 'name'
                              editorOptions.searchEnabled = true
                              editorOptions.showClearButton = true

                              if (!editorType || editorType === 'dxTextBox') {
                                editorType = 'dxSelectBox'
                              }
                            }

                            const item: any = {
                              dataField: i.dataField,
                              editorType: editorType,
                              colSpan: i.colSpan,
                              isRequired: i.isRequired,
                              editorOptions,
                            }

                            // Required field için validasyon kuralı ekle
                            if (i.isRequired) {
                              item.validationRules = [
                                {
                                  type: 'required',
                                  message: `${i.dataField.split(':')[1] || i.dataField} zorunludur`,
                                },
                              ]
                            }

                            if (i.dataField.indexOf(':') >= 0) {
                              item.label = { text: captionize(i.dataField.split(':')[1]) }
                            }

                            return item
                          }

                          sortedFormDto.forEach((e: any) => {
                            if (e.itemType !== 'tabbed') {
                              result.push({
                                itemType: e.itemType,
                                colCount: e.colCount || 1,
                                colSpan: e.colSpan || 1,
                                caption: e.caption,
                                items: e.items
                                  ?.sort((a: any, b: any) => (a.order >= b.order ? 1 : -1))
                                  .map(mapFormItem),
                              })
                            } else if (tabbedItems.length > 0 && e === tabbedItems[0]) {
                              result.push({
                                itemType: 'tabbed',
                                colCount: 1,
                                colSpan: 1,
                                tabs: tabbedItems.map((tabbedItem: any) => ({
                                  title: tabbedItem.caption,
                                  colCount: tabbedItem.colCount || 1,
                                  items: tabbedItem.items
                                    ?.sort((a: any, b: any) => (a.order >= b.order ? 1 : -1))
                                    .map(mapFormItem),
                                })),
                              })
                            }
                          })

                          return result
                        })()
                      : undefined,
                }}
              />

              {/* Columns */}
              {renderColumns()}
            </CardViewDx>
          </div>
        )}
      </Container>
    </>
  )
}

export default CardView
