import { useMemo, useCallback } from 'react';
import { useLocation } from 'react-router-dom';
import {
  CrudFilters,
  HttpError,
  parseTableParams,
  unionFilters,
  useExport,
  useTranslate,
  useUpdate,
  useApiUrl,
  BaseRecord,
} from '@refinedev/core';
import { useTable, useImport } from '@refinedev/antd';
import dayjs from 'dayjs';
import { useBatchOperations } from './useBatchOperations';
import { ListPageConfig, UseListPageStateResult } from './types';
import {
  ModelType,
  FieldDataType,
  produceModel,
  getColumns,
  tableSearchBar,
} from '@gadmin2n/react-common';

export interface UseListPageStateConfig {
  resourceName: string;
  /** Raw model from generated code */
  rawModel: ModelType;
  /** Model customizations */
  modelOverrides?: Record<string, Partial<FieldDataType>>;
  tableConfig: ListPageConfig['tableConfig'];
  prismaSelect?: any;
  modelsMap: ListPageConfig['modelsMap'];
  modelsEnum: ListPageConfig['modelsEnum'];
  /** API URL, will use useApiUrl() if not provided */
  apiUrl?: string;
  /** Function to get request headers for batch operations */
  requestHeaders?: () => Record<string, string>;
  /** Hook to get relation select props */
  useRelation?: (modelsMap: ListPageConfig['modelsMap']) => Record<string, any>;
  /** Search fields configuration */
  searchFields?: {
    keyword?: string;
    dateRange?: string[];
  };
}

/**
 * Comprehensive hook that provides all state and handlers for a list page
 */
export function useListPageState<T extends BaseRecord = any>({
  resourceName,
  rawModel,
  modelOverrides = {},
  tableConfig,
  prismaSelect,
  modelsMap,
  modelsEnum,
  apiUrl: customApiUrl,
  requestHeaders,
  useRelation,
  searchFields = { keyword: 'q', dateRange: ['createdAt'] },
}: UseListPageStateConfig): UseListPageStateResult {
  const t = useTranslate();
  const defaultApiUrl = useApiUrl();
  const apiUrl = customApiUrl || defaultApiUrl;
  const { search } = useLocation();

  // Parse initial filters and sorters from URL
  const { parsedSorter, parsedFilters } = parseTableParams(search);

  // Create model with customizations
  const [columns, model] = useMemo(() => {
    const model: ModelType = produceModel(rawModel, modelOverrides);
    const modelName =
      resourceName.charAt(0).toUpperCase() + resourceName.slice(1);

    const columns = getColumns(modelName, tableConfig.fields, {
      ...modelsMap,
      [modelName]: { model, meta: modelsMap[modelName]?.meta },
    });

    return [columns, model] as const;
  }, [rawModel, modelOverrides, tableConfig.fields, modelsMap, resourceName]);

  // Get search bar configuration
  const { placeholder: searchPlaceholder, getSearchFilters } = useMemo(
    () => tableSearchBar(tableConfig.toolbar.searchBar, rawModel),
    [tableConfig.toolbar.searchBar, rawModel],
  );

  // Table hook
  const {
    tableProps,
    sorters: sorter,
    filters,
    setCurrent,
    setFilters,
    searchFormProps,
    tableQueryResult,
  } = useTable<T, HttpError, T & { q: string }>({
    meta: {
      transformQFn: getSearchFilters,
      select: prismaSelect,
    },
    filters: {
      initial: parsedFilters,
      defaultBehavior: 'merge',
    },
    sorters: {
      initial: parsedSorter,
    },
  });

  // Initialize search form values
  const keywordField = searchFields.keyword || 'q';
  const dateRangeField = searchFields.dateRange?.[0] || 'createdAt';

  searchFormProps.initialValues = useMemo(
    () => ({
      [keywordField]: parsedFilters.find((f: any) => f.field === keywordField)
        ?.value,
      [dateRangeField]: parsedFilters.find(
        (f: any) => f.field === dateRangeField && f.operator === 'gte',
      )
        ? [
            dayjs(
              parsedFilters.find(
                (f: any) => f.field === dateRangeField && f.operator === 'gte',
              )?.value,
            ),
            dayjs(
              parsedFilters.find(
                (f: any) => f.field === dateRangeField && f.operator === 'lte',
              )?.value,
            ),
          ]
        : [undefined, undefined],
    }),
    [parsedFilters, keywordField, dateRangeField],
  );

  // Search form submit handler
  searchFormProps.onFinish = useCallback(
    (values: any) => {
      const fs: CrudFilters = [];
      const keyword = (values[keywordField] || '').trim();
      const dateRange = values[dateRangeField];

      if (dateRange && dateRange[0]) {
        fs.push(
          {
            field: dateRangeField,
            operator: 'gte',
            value: dateRange[0]?.toISOString?.(),
          },
          {
            field: dateRangeField,
            operator: 'lte',
            value: dateRange[1]?.toISOString?.(),
          },
        );
      }

      if (keyword) {
        fs.push({
          field: keywordField,
          operator: 'eq',
          value: keyword,
        });
      }

      setCurrent(1);
      setFilters((prevFilters) =>
        unionFilters(
          [],
          fs,
          prevFilters.filter(
            (item: any) => ![keywordField, dateRangeField].includes(item.field),
          ),
        ),
      );
    },
    [keywordField, dateRangeField, setCurrent, setFilters],
  );

  // Batch operations
  const batchOps = useBatchOperations({
    resourceName,
    apiUrl,
    requestHeaders,
    onSuccess: () => tableQueryResult.refetch(),
    t,
  });

  // Export hooks
  const { triggerExport: triggerExportAll, isLoading: exportLoading } =
    useExport<T>({
      maxItemCount: 200,
      pageSize: 100,
    });

  const {
    triggerExport: triggerExportSelected,
    isLoading: exportSelectedLoading,
  } = useExport<T>({
    pageSize: 100,
    meta: {
      where: { id: { in: batchOps.selectedRowKeys.map(Number) } },
    },
  });

  // Import hook
  const importProps = useImport<T>({
    mapData: (item: any) => ({ ...item }),
    batchSize: 1,
  });

  // Row update
  const { mutate: updateRow, isLoading: isUpdateRowLoading } = useUpdate();
  const updateRowData = useCallback(
    (id: number, values: any) => {
      updateRow({
        resource: resourceName,
        id,
        values,
      });
    },
    [updateRow, resourceName],
  );

  // Get relation select props
  const relationResult = useRelation?.(modelsMap) || {};
  const relationSelectProps = useMemo(() => relationResult, [relationResult]);

  // Build context
  const context = useMemo(
    () => ({
      resourceName,
      t,
      model,
      modelsMap,
      modelsEnum,
      tableConfig,
      apiUrl,
      relationSelectProps,
      searchPlaceholder,
    }),
    [
      resourceName,
      t,
      model,
      modelsMap,
      modelsEnum,
      tableConfig,
      apiUrl,
      relationSelectProps,
      searchPlaceholder,
    ],
  );

  return {
    // Table related
    tableProps,
    columns,
    model,
    sorter,
    filters,

    // Search related
    searchFormProps,

    // Selection related
    selectedRowKeys: batchOps.selectedRowKeys,
    setSelectedRowKeys: batchOps.setSelectedRowKeys,
    rowSelection: batchOps.rowSelection,
    hasSelected: batchOps.hasSelected,

    // Batch operations
    updateSelectedItems: batchOps.updateSelectedItems,
    deleteSelectedItems: batchOps.deleteSelectedItems,
    updateManyIsLoading: batchOps.updateManyIsLoading,
    deleteManyIsLoading: batchOps.deleteManyIsLoading,

    // Export/Import
    triggerExportAll,
    triggerExportSelected,
    exportLoading,
    exportSelectedLoading,
    importProps,

    // Row operations
    updateRowData,
    isUpdateRowLoading,

    // Context
    context,

    // Refetch
    refetch: tableQueryResult.refetch,
  };
}
