import { DownOutlined, SearchOutlined } from '@ant-design/icons';
import {
  getColumns,
  ModelType,
  tableSearchBar,
  whenIsTrue,
} from '@gadmin2/react-common';
import {
  CloneButton,
  CreateButton,
  DeleteButton,
  EditButton,
  ExportButton,
  ImportButton,
  List,
  ShowButton,
  useImport,
  useTable,
} from '@refinedev/antd';
import {
  CrudFilters,
  HttpError,
  IResourceComponentsProps,
  parseTableParams,
  unionFilters,
  useDeleteMany,
  useExport,
  useTranslate,
  useUpdate,
  useUpdateMany,
} from '@refinedev/core';
import {
  Button,
  DatePicker,
  Dropdown,
  Form,
  FormProps,
  Input,
  Popconfirm,
  Space,
  Table,
} from 'antd';
import { LogButton } from 'components/auditLog';
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 {
  gameTableConfig as tableConfig,
  gameTablePrismaSelect as prismaSelect,
} from '../../generated/props/game/config';
import { gameModel, useRelation } from '../../generated/props/game/model';
import type { Game } from '../../generated/types/prisma.types'; //'.prisma/client/index';
import { getTableColumn } from '../../helpers';

const { RangePicker } = DatePicker;

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

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

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

// https://refine.dev/docs/api-reference/antd/hooks/table/useTable/
export const GameList: React.FC<IResourceComponentsProps> = () => {
  const resourceName = 'game';
  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<Game, HttpError, Game & { 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,
    create_time: parsedFilters.find(
      (f: any) => f.field === 'create_time' && f.operator === 'gte',
    )
      ? [
          dayjs(
            parsedFilters.find(
              (f: any) => f.field === 'create_time' && f.operator === 'gte',
            )?.value,
          ),
          dayjs(
            parsedFilters.find(
              (f: any) => f.field === 'create_time' && f.operator === 'lte',
            )?.value,
          ),
        ]
      : [undefined, undefined],
  };

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

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

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

    setFilters((prevFilters) =>
      unionFilters(
        [],
        fs,
        prevFilters.filter(
          (item: any) => !['q', 'create_time'].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<Game>();
  const updateSelectedItems = (values: any) => {
    updateMany(
      {
        resource: resourceName,
        ids: selectedRowKeys.map(Number),
        values,
      },
      {
        onSuccess: () => {
          setSelectedRowKeys([]);
        },
      },
    );
  };

  const {
    triggerExport: triggerExportSelected,
    isLoading: isExportSelectedLoading,
  } = useExport<Game>({
    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 { mutate: deleteMany, isLoading: deleteManyIsLoading } =
    useDeleteMany<Game>();
  const deleteSelectedItems = () => {
    deleteMany(
      {
        resource: resourceName,
        ids: selectedRowKeys.map(Number),
      },
      {
        onSuccess: () => {
          setSelectedRowKeys([]);
        },
      },
    );
  };

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

  const importProps = useImport<Game>({
    mapData: (item: any) => {
      return {
        ...item,
      };
    },

    batchSize: 100,
  });

  const { mutate: updateRow, isLoading: isUpdateRowLoading } = useUpdate();
  const updateRowData = (id: number, values: any) => {
    updateRow({
      resource: resourceName,
      id,
      values,
    });
  };

  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.game.actions.' + action.desc, action.desc)}
                  </Button>
                </Popconfirm>
              ))}
            <ExportButton
              onClick={triggerExportSelected}
              loading={isExportSelectedLoading}
              icon={<></>}
            />
            <Popconfirm
              placement="top"
              onConfirm={deleteSelectedItems}
              title={t('buttons.confirm', 'Are you sure?')}
              okText={t('buttons.sure', 'Yes')}
              cancelText={t('buttons.cancel', 'No')}
            >
              <Button danger loading={deleteManyIsLoading}>
                {t('buttons.delete', 'Delete')}
              </Button>
            </Popconfirm>
            <span style={{ marginLeft: 8 }}>
              {t('table.selected', 'Selected') +
                ' ' +
                selectedRowKeys.length +
                ' ' +
                t('table.items', 'items')}
            </span>
          </Space>
        ),
        extra: (
          <Space>
            <ImportButton {...importProps} />
            <ExportButton onClick={triggerExportAll} loading={exportLoading} />
            <CreateButton type="primary" />
          </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<Game>
          title={t('table.actions')}
          dataIndex="actions"
          render={(_, record) => {
            return (
              <Space>
                <EditButton
                  icon={false}
                  type="text"
                  size="small"
                  recordItemId={record.id}
                />
                <ShowButton
                  icon={false}
                  type="text"
                  size="small"
                  recordItemId={record.id}
                >
                  {t('table.detail')}
                </ShowButton>

                <Dropdown
                  menu={{
                    items: [
                      ...tableConfig.rowActions.actions
                        .filter((action) => action.action === 'CHANGE_STATUS')
                        .map((action) => ({
                          label: (
                            <Popconfirm
                              placement="top"
                              title={t('buttons.confirm', 'Are you sure?')}
                              onConfirm={() =>
                                updateRowData(record.id, (action as any).values)
                              }
                              okText={t('buttons.sure', 'Yes')}
                              cancelText={t('buttons.cancel', 'No')}
                              disabled={!whenIsTrue(action.when, record)}
                            >
                              <Button
                                loading={isUpdateRowLoading}
                                size="small"
                                type="text"
                                disabled={!whenIsTrue(action.when, record)}
                              >
                                {t(
                                  'resources.game.actions.' + action.desc,
                                  action.desc,
                                )}
                              </Button>
                            </Popconfirm>
                          ),
                          key: action.desc,
                        })),
                      {
                        label: (
                          <CloneButton
                            icon={false}
                            type="text"
                            size="small"
                            recordItemId={record.id}
                          />
                        ),
                        key: 'clone',
                      },
                      {
                        label: (
                          <LogButton
                            hideText={false}
                            icon={false}
                            type="text"
                            size="small"
                            recordItemId={record.id}
                          />
                        ),
                        key: 'history',
                      },
                      {
                        label: (
                          <DeleteButton
                            icon={false}
                            type="text"
                            size="small"
                            recordItemId={record.id}
                          />
                        ),
                        key: 'delete',
                      },
                    ] as any,
                  }}
                  trigger={['click']}
                >
                  <Button type="text" size="small">
                    {t('table.more', 'More')}
                    <DownOutlined />
                  </Button>
                </Dropdown>
              </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.game.search.q.title', 'Search')}
          name="q"
          style={{ width: '100%', maxWidth: '300px' }}
        >
          <Input
            placeholder={t(
              'resources.game.search.q.placeholder',
              searchPlaceholder,
            )}
            prefix={<SearchOutlined />}
          />
        </Form.Item>
        &nbsp;
        <Form.Item
          label={t('resources.game.fields.create_time', 'create_time')}
          name="create_time"
          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>
  );
};
