import { CommonProps } from '@/proxy/common'
import { Meta } from '@/proxy/routes/routes'
import { Container } from '@/components/shared'
import { APP_NAME, DX_CLASSNAMES } from '@/constants/app.constant'
import { useLocalization } from '@/utils/hooks/useLocalization'
import DxChart from 'devextreme-react/chart'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { Helmet } from 'react-helmet'
import { useParams, useSearchParams } from 'react-router-dom'
import { GridDto } from '@/proxy/form/models'
import { usePermission } from '@/utils/hooks/usePermission'
import { Button, toast, Notification } from '@/components/ui'
import { ROUTES_ENUM } from '@/routes/route.constant'
import { usePWA } from '@/utils/hooks/usePWA'
import { FaCog, FaCrosshairs, FaSearch, FaSyncAlt } from 'react-icons/fa'
import { buildSeriesDto } from './Utils'
import { ChartSeriesDto } from '@/proxy/admin/charts/models'
import { SelectBoxOption } from '@/types/shared'
import { useStoreState } from '@/store/store'
import ChartDrawer from './ChartDrawer'
import { getListFormFields } from '@/services/admin/list-form-field.service'
import { groupBy } from 'lodash'
import { ListFormJsonRowDto } from '@/proxy/admin/list-form/models'
import { ListFormEditTabs } from '@/proxy/admin/list-form/options'
import {
  deleteListFormJsonRow,
  postListFormJsonRow,
  putListFormJsonRow,
} from '@/services/admin/list-form.service'
import { layoutTypes } from '../admin/listForm/edit/types'
import { useListFormCustomDataSource } from './useListFormCustomDataSource'

interface ChartProps extends CommonProps, Meta {
  id: string
  listFormCode: string
  filter?: string
  isSubForm?: boolean
  level?: number
  refreshData?: () => Promise<void>
  gridDto?: GridDto
  refreshGridDto?: () => Promise<void>
}

const Chart = (props: ChartProps) => {
  // State UserId güncellemesi için
  const { userName } = useStoreState((s) => s.auth.user)
  const { id, listFormCode, filter, isSubForm, level, gridDto, refreshGridDto } = props
  const { translate } = useLocalization()
  const { checkPermission } = usePermission()
  const isPwaMode = usePWA()
  const [initialized, setInitialized] = useState(false)

  const [searchParams] = useSearchParams()
  const [chartOptions, setChartOptions] = useState<any>()
  const { createSelectDataSource } = useListFormCustomDataSource({} as any)
  const config = useStoreState((state) => state.abpConfig.config)

  const params = useParams()
  const _listFormCode = props?.listFormCode ?? params?.listFormCode ?? ''

  const [openDrawer, setOpenDrawer] = useState(false)
  const [fieldList, setFieldList] = useState<SelectBoxOption[]>([])
  
  // Ana state - Chart bu state'e göre render edilir
  const [currentSeries, setCurrentSeries] = useState<ChartSeriesDto[]>([])
  
  // Veritabanından gelen orijinal seriler (kaydetme işlemi için)
  const [savedSeries, setSavedSeries] = useState<ChartSeriesDto[]>([])

  const [searchText, setSearchText] = useState('')
  const [prevValue, setPrevValue] = useState('')
  const [urlSearchParams, setUrlSearchParams] = useState<URLSearchParams>(
    searchParams ? new URLSearchParams(searchParams) : new URLSearchParams(),
  )

  const [allSeries, setAllSeries] = useState<ChartSeriesDto[]>([])

  useEffect(() => {
    if (gridDto) {
      const initialSeries = gridDto.gridOptions.seriesDto.map((s, index) => ({ ...s, index }))
      const userSeriesData = initialSeries.filter((s) => s.userId === userName)

      setAllSeries(initialSeries)
      
      // Kullanıcının serisi varsa onu kullan, yoksa tüm serileri kullan
      const seriesToUse = userSeriesData.length > 0 ? userSeriesData : initialSeries
      
      // Sadece ilk yüklemede VEYA refresh sonrası güncelle
      if (!initialized) {
        setCurrentSeries(seriesToUse)
        setSavedSeries(seriesToUse)
        setInitialized(true)
      } else {
        // Refresh sonrası - yeni kaydedilen serileri kullan
        setCurrentSeries(seriesToUse)
        setSavedSeries(seriesToUse)
      }
    }
  }, [gridDto, userName])

  const memoizedChartOptions = useMemo(() => {
    if (!gridDto || !initialized) return undefined

    const seriesDto = currentSeries

    const gridOptions = {
      ...gridDto.gridOptions,
      seriesDto,
    }

    const dataSource = createSelectDataSource(
      gridOptions,
      listFormCode,
      urlSearchParams,
      layoutTypes.chart,
    )

    return {
      dataSource: dataSource,

      adjustOnZoom: gridDto.gridOptions.commonDto?.adjustOnZoom ?? true,
      containerBackgroundColor:
        gridDto.gridOptions.commonDto?.containerBackgroundColor ?? '#FFFFFF',
      disabled: gridDto.gridOptions.commonDto?.disabled ?? false,
      palette: gridDto.gridOptions.commonDto?.palette ?? 'Material',
      paletteExtensionMode: gridDto.gridOptions.commonDto?.paletteExtensionMode ?? 'blend',

      title: gridDto.gridOptions.titleDto,
      size: gridDto.gridOptions.sizeDto?.useSize
        ? { width: gridDto.gridOptions.sizeDto.width, height: gridDto.gridOptions.sizeDto.height }
        : { 
            width: openDrawer ? window.innerWidth - 550 : '100%', 
            height: window.innerHeight - 210 
          },
      legend: gridDto.gridOptions.legendDto || {
        visible: true,
        verticalAlignment: 'bottom',
        horizontalAlignment: 'center',
      },
      margin: gridDto.gridOptions.marginDto,
      adaptiveLayout: gridDto.gridOptions.adaptivelayoutDto,
      defaultPane: gridDto.gridOptions.commonDto?.defaultPane,

      scrollBar: gridDto.gridOptions.scrollBarDto,
      zoomAndPan: gridDto.gridOptions.zoomAndPanDto,
      animation: gridDto.gridOptions.animationDto,
      export: gridDto.gridOptions.exportDto,
      crosshair: gridDto.gridOptions.crosshairDto,
      argumentAxis: gridDto.gridOptions.argumentAxisDto,
      valueAxis: gridDto.gridOptions.valueAxisDto,
      tooltip: gridDto.gridOptions.tooltipDto || {
        enabled: true,
        shared: false,
        format: 'decimal',
      },

      series: buildSeriesDto(seriesDto),

      panes: gridDto.gridOptions.panesDto?.length > 0 ? gridDto.gridOptions.panesDto : undefined,
      commonSeriesSettings: gridDto.gridOptions.commonSeriesSettingsDto,
      commonPaneSettings: gridDto.gridOptions.commonPaneSettingsDto,
      commonAxisSettings: gridDto.gridOptions.commonAxisSettingsDto,
      annotations: gridDto.gridOptions.annotationsDto,
      commonAnnotationSettings: gridDto.gridOptions.commonAnnotationSettingsDto,

      loadingIndicator: {
        enabled: true,
      },
    }
  }, [gridDto, currentSeries, initialized, createSelectDataSource, listFormCode, urlSearchParams, openDrawer])

  useEffect(() => {
    if (memoizedChartOptions) {
      setChartOptions(memoizedChartOptions)
    }
  }, [memoizedChartOptions])

  const onFilter = useCallback(
    (value?: string) => {
      const text = value !== undefined ? value.trim() : searchText.trim()

      if (!gridDto?.columnFormats) return

      const newParams = new URLSearchParams(urlSearchParams.toString())

      if (!text) {
        newParams.delete('filter')
        setUrlSearchParams(newParams)
        return
      }

      const merged = gridDto.columnFormats
        .filter(
          (col) =>
            col.dataType === 'string' &&
            col.visible &&
            col.width &&
            col.allowSearch &&
            col.width > 0,
        )
        .map((col) => [col.fieldName, 'contains', text])

      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, 'or', f]
        }, null as any)
      }

      if (filter) {
        newParams.set('filter', JSON.stringify(filter))
      } else {
        newParams.delete('filter')
      }

      setUrlSearchParams(newParams)
    },
    [gridDto, urlSearchParams, searchText],
  )

  const getFields = useCallback(async () => {
    if (!props.listFormCode) return
    try {
      const resp = await getListFormFields({
        listFormCode: props.listFormCode,
        sorting: 'ListOrderNo',
        maxResultCount: 1000,
      })
      if (resp.data?.items) {
        const fieldNames = groupBy(resp?.data?.items, 'fieldName')
        setFieldList(Object.keys(fieldNames).map((fieldName) => {
          const firstItem = fieldNames[fieldName][0]
          const label = firstItem.captionName 
            ? translate('::' + firstItem.captionName) 
            : fieldName
          return { value: fieldName, label }
        }))
      }
    } catch (error: any) {
      toast.push(
        <Notification type="danger" duration={2000}>
          Alanlar getirilemedi {error.toString()}
        </Notification>,
        { placement: 'top-end' },
      )
    }
  }, [props.listFormCode, translate])

  useEffect(() => {
    if (props.listFormCode) getFields()
  }, [props.listFormCode, config])

  const handlePreviewChange = useCallback((series: ChartSeriesDto[]) => {
    // Preview değişikliklerini anında chart'a yansıt
    setCurrentSeries(series)
  }, [])

  const handleDrawerClose = useCallback(() => {
    setOpenDrawer(false)
    // İptal - kaydedilmiş serilere geri dön
    setCurrentSeries(savedSeries)
  }, [savedSeries])

  const onSave = useCallback(async (newSeries: ChartSeriesDto[]) => {
    // 1. Silinecek serileri bul (savedSeries var ama newSeries yok)
    const toDelete = savedSeries.filter((old: ChartSeriesDto) => !newSeries.some((s) => s.index === old.index))

    // Index kaymasını önlemek için büyükten küçüğe sırala
    toDelete.sort((a: ChartSeriesDto, b: ChartSeriesDto) => b.index - a.index)

    for (const old of toDelete) {
      await deleteListFormJsonRow(id, ListFormEditTabs.ChartSeries.GeneralJsonRow, old.index)
    }

    // 2. Yeni veya güncellenen serileri kaydet
    for (const series of newSeries) {
      const input: ListFormJsonRowDto = {
        index: series.index,
        fieldName: ListFormEditTabs.ChartSeries.GeneralJsonRow,
        itemChartSeries: series,
      }

      if (series.index === -1) {
        await postListFormJsonRow(id, input)
      } else {
        await putListFormJsonRow(id, input)
      }
    }

    // 3. Yeniden yükle (veritabanından fresh data)
    if (props.refreshGridDto) {
      setInitialized(false)
      await props.refreshGridDto()
      // refreshGridDto tamamlandıktan sonra yeni state'ler otomatik setlenecek
    } else {
      // refreshGridDto yoksa manuel güncelle
      setSavedSeries(newSeries)
      setCurrentSeries(newSeries)
    }
  }, [savedSeries, id, props])

  return (
    <Container className={DX_CLASSNAMES}>
      {!isSubForm && gridDto && (
        <Helmet
          titleTemplate={`%s | ${APP_NAME}`}
          title={translate('::' + gridDto?.gridOptions?.title)}
          defaultTitle={APP_NAME}
        ></Helmet>
      )}
      {_listFormCode && chartOptions && (
        <div className="p-1 bg-white dark:bg-neutral-800 dark:border-neutral-700 h-full relative">
          <div className="flex justify-end items-center h-full">
            <div className="relative pb-1 flex gap-1 border-b-1">
              <FaSearch className="absolute left-2 top-1/2 -translate-y-1/2 text-gray-400 text-sm" />
              <input
                type="text"
                placeholder={translate('::App.Search')}
                value={searchText}
                onChange={(e) => setSearchText(e.target.value)}
                onKeyDown={(e) => {
                  if (e.key === 'Enter') {
                    onFilter(e.currentTarget.value)
                    setPrevValue(e.currentTarget.value.trim()) // Enter ile tetiklenirse güncelle
                  }
                }}
                onBlur={(e) => {
                  const newValue = e.currentTarget.value.trim()

                  // 1. Değer değişmemişse => hiçbir şey yapma
                  if (newValue === prevValue) return

                  // 2. Yeni değer boş, ama eskiden değer vardı => filtre temizle
                  // 3. Yeni değer dolu ve eskisinden farklı => filtre uygula
                  onFilter(newValue)
                  setPrevValue(newValue)
                }}
                className="p-1 pl-6 pr-2 border border-1 outline-none text-xs text-gray-700 dark:text-gray-200 placeholder-gray-400 rounded"
              />
              <Button
                size="sm"
                variant={'default'}
                className="text-sm flex items-center gap-1"
                onClick={async () => {
                  setInitialized(false)
                  await refreshGridDto?.()
                }}
                title={translate('::App.Platform.Refresh')} 
              >
                <FaSyncAlt className="w-3 h-3" /> {translate('::App.Platform.Refresh')}
              </Button>
              <Button
                size="sm"
                variant="default"
                className="text-sm flex items-center gap-1"
                onClick={() => setOpenDrawer(true)}
                title={translate('::ListForms.ListFormEdit.TabChartSeries')}
              >
                <FaCrosshairs className="w-3 h-3" /> {translate('::ListForms.ListFormEdit.TabChartSeries')}
              </Button>

              {checkPermission(gridDto?.gridOptions.permissionDto.u) && (
                <Button
                  size="sm"
                  variant={'default'}
                  className="text-sm"
                  onClick={() => {
                    window.open(
                      ROUTES_ENUM.protected.saas.listFormManagement.edit.replace(
                        ':listFormCode',
                        listFormCode,
                      ),
                      isPwaMode ? '_self' : '_blank',
                    )
                  }}
                  title={translate('::ListForms.ListForm.Manage')}
                >
                  <FaCog className="w-3 h-3" />
                </Button>
              )}
            </div>
          </div>
          <div 
            className={`transition-all duration-300 ${openDrawer ? 'mr-[500px]' : 'mr-0'}`}
            style={{ width: openDrawer ? 'calc(100% - 500px)' : '100%' }}
          >
            <DxChart key={'DxChart' + _listFormCode} {...chartOptions}></DxChart>
          </div>

          <ChartDrawer
            open={openDrawer}
            onClose={handleDrawerClose}
            initialSeries={currentSeries}
            fieldList={fieldList}
            onSave={onSave}
            onPreviewChange={handlePreviewChange}
          />
        </div>
      )}
    </Container>
  )
}

export default Chart
