import { SearchOutlined } from '@ant-design/icons';
import {
  getColumns,
  ModelType,
  tableSearchBar,
} from '@gadmin2/react-common';
import {
  ExportButton,
  List,
  ShowButton,
  useTable,
} from '@refinedev/antd';
import {
  CrudFilters,
  HttpError,
  IResourceComponentsProps,
  parseTableParams,
  unionFilters,
  useExport,
  useTranslate,
  useUpdateMany,
} from '@refinedev/core';
import {
  Button,
  DatePicker,
  Form,
  FormProps,
  Input,
  Popconfirm,
  Space,
  Table,
} from 'antd';
import dayjs from 'dayjs';
import produce from 'immer';
import React from 'react';
import { useLocation } from 'react-router-dom';
import { modelsEnum, modelsMap } from '../../generated/models.index';
import {
  logTableConfig as tableConfig,
  logTablePrismaSelect as prismaSelect,
} from '../../generated/props/log/config';
import { logModel, useRelation } from '../../generated/props/log/model';
import type { Log } from '../../generated/types/prisma.types'; //'.prisma/client/index';
import { getTableColumn } from '../../helpers';

const { RangePicker } = DatePicker;

const model: ModelType = produce(logModel, () => {
  /*
  const publishedColumn = draft["published"] || {};
  publishedColumn.width = 100;
  publishedColumn.render = (value: any, record: Log) => {
    let color;
    switch (value) {
      case modelsEnum["Status"]["PUBLISHED"]:
        color = "green";
        break;
      default:
        color = "";
        break;
    }
    return <TagField color={color} value={value} />;
  };
  */
});

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

const { placeholder: searchPlaceholder, getSearchFilters } = tableSearchBar(
  tableConfig['toolbar']['searchBar'],
  model,
);

// https://refine.dev/docs/api-reference/antd/hooks/table/useTable/
export const LogList: React.FC<IResourceComponentsProps> = () => {
  const resourceName = 'log';
  const t = useTranslate();

  const relationSelectProps = useRelation(modelsMap);

  const { search } = useLocation();
  // We want to always parse the query string even when syncWithLocation is
  // deactivated, for hotlinking to work properly.
  const { parsedSorter, parsedFilters } = parseTableParams(search);

  const {
    tableProps,
    sorters: sorter,
    filters,
    setFilters,
    searchFormProps,
  } = useTable<Log, HttpError, Log & { q: string }>({
    meta: {
      transformQFn: getSearchFilters,
      select: prismaSelect,
    },

    filters: {
      initial: parsedFilters,
      defaultBehavior: 'merge',
    },

    sorters: {
      initial: parsedSorter,
    },
  });

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

  searchFormProps.onFinish = (values) => {
    const fs: CrudFilters = [];
    const { q, timestamp } = values;
    const trimedQ = (q || '').trim();

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

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

    setFilters((prevFilters) =>
      unionFilters(
        [],
        fs,
        prevFilters.filter(
          (item: any) => !['q', 'timestamp'].includes(item.field),
        ),
      ),
    );
  };

  // https://refine.dev/docs/examples/table/antd/advancedTable/
  const [selectedRowKeys, setSelectedRowKeys] = React.useState<React.Key[]>([]);
  const onSelectChange = (selectedRowKeys: React.Key[]) => {
    setSelectedRowKeys(selectedRowKeys);
  };
  const rowSelection = {
    selectedRowKeys,
    onChange: onSelectChange,
  };
  const hasSelected = selectedRowKeys.length > 0;

  // https://refine.dev/docs/examples/table/antd/useUpdateMany/
  const { mutate: updateMany, isLoading: updateManyIsLoading } =
    useUpdateMany<Log>();
  const updateSelectedItems = (values: any) => {
    updateMany(
      {
        resource: resourceName,
        ids: selectedRowKeys.map(Number),
        values,
      },
      {
        onSuccess: () => {
          setSelectedRowKeys([]);
        },
      },
    );
  };

  const {
    triggerExport: triggerExportSelected,
    isLoading: isExportSelectedLoading,
  } = useExport<Log>({
    pageSize: 100,
    /*
    mapData: (item) => {
      return {
        id: item.id,
        name: item.name,
        desc: item.description,
        sku: item.sku,
      };
    },
    */
    meta: {
      where: { id: { in: selectedRowKeys.map(Number) } },
    },
  });

  const { triggerExport: triggerExportAll, isLoading: exportLoading } =
    useExport<Log>({
      maxItemCount: 200,
      pageSize: 100,
      /*
      mapData: (item) => {
        return {
          id: item.id,
          name: item.name,
          desc: item.description,
          sku: item.sku,
        };
      },
      */
    });

  return (
    <List
      headerProps={{
        subTitle: hasSelected && (
          <Space>
            {tableConfig.rowSelection.actions
              .filter((action) => action.action === 'CHANGE_STATUS')
              .map((action) => (
                <Popconfirm
                  placement="top"
                  onConfirm={() => updateSelectedItems((action as any).values)}
                  title={t('buttons.confirm', 'Are you sure?')}
                  okText={t('buttons.sure', 'Yes')}
                  cancelText={t('buttons.cancel', 'No')}
                >
                  <Button type="default" loading={updateManyIsLoading}>
                    {t('resources.log.actions.' + action.desc, action.desc)}
                  </Button>
                </Popconfirm>
              ))}
            <ExportButton
              onClick={triggerExportSelected}
              loading={isExportSelectedLoading}
              icon={<></>}
            />
            <span style={{ marginLeft: 8 }}>
              {t('table.selected', 'Selected') +
                ' ' +
                selectedRowKeys.length +
                ' ' +
                t('table.items', 'items')}
            </span>
          </Space>
        ),
        extra: (
          <Space>
            <ExportButton onClick={triggerExportAll} loading={exportLoading} />
          </Space>
        ),
      }}
    >
      <Search formProps={searchFormProps} />

      <Table {...tableProps} rowKey="id" rowSelection={rowSelection}>
        {columns.map((col) => {
          return getTableColumn(
            col,
            resourceName,
            t,
            model,
            modelsEnum,
            modelsMap,
            tableConfig,
            sorter,
            filters,
            relationSelectProps,
          );
        })}

        <Table.Column<Log>
          title={t('table.actions')}
          dataIndex="actions"
          render={(_, record) => {
            return (
              <Space>
                <ShowButton
                  icon={false}
                  type="text"
                  size="small"
                  recordItemId={record.id}
                >
                  {t('table.detail')}
                </ShowButton>
              </Space>
            );
          }}
        />
      </Table>
    </List>
  );
};

// https://refine.dev/docs/advanced-tutorials/search/list-search/
const Search: React.FC<{ formProps: FormProps }> = ({ formProps }) => {
  const t = useTranslate();

  return (
    <Form {...formProps}>
      <Space wrap>
        <Form.Item
          label={t('resources.log.search.q.title', 'Search')}
          name="q"
          style={{ width: '100%', maxWidth: '300px' }}
        >
          <Input
            placeholder={t(
              'resources.log.search.q.placeholder',
              searchPlaceholder,
            )}
            prefix={<SearchOutlined />}
          />
        </Form.Item>
        &nbsp;
        <Form.Item
          label={t('resources.log.fields.timestamp', 'OperateTime')}
          name="timestamp"
          style={{ width: '100%', maxWidth: '400px' }}
        >
          <RangePicker />
        </Form.Item>
        &nbsp;
        <Form.Item>
          <Button htmlType="submit" type="primary">
            {t('buttons.filter', 'Filter')}
          </Button>
        </Form.Item>
      </Space>
    </Form>
  );
};
