/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { DownOutlined, ImportOutlined, PlusOutlined } from '@ant-design/icons';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import type { ActionType, ProColumns } from '@ant-design/pro-table';
import ProTable from '@ant-design/pro-table';
import { useThrottleFn } from 'ahooks';
import {
  Button,
  Dropdown,
  Menu,
  Modal,
  notification,
  Popconfirm,
  Select,
  Space,
  Table,
  Tag,
  Tooltip,
} from 'antd';
import { omit } from 'lodash';
import type { ReactNode } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import { history, useIntl } from 'umi';

import { RawDataEditor } from '@/components/RawDataEditor';
import { DELETE_FIELDS } from '@/constants';
import { timestampToLocaleString } from '@/helpers';
import usePagination from '@/hooks/usePagination';
import DataLoaderImport from '@/pages/Route/components/DataLoader/Import';

import { DebugDrawView } from './components/DebugViews';
import { create, fetchLabelList, fetchList, remove, update, updateRouteStatus } from './service';

const { OptGroup, Option } = Select;

const Page: React.FC = () => {
  const ref = useRef<ActionType>();
  const { formatMessage } = useIntl();

  enum RouteStatus {
    Offline = 0,
    Publish,
  }

  const [labelList, setLabelList] = useState<LabelList>({});
  const [selectedRowKeys, setSelectedRowKeys] = useState<string[]>([]);
  const [showImportDrawer, setShowImportDrawer] = useState(false);
  const [visible, setVisible] = useState(false);
  const [rawData, setRawData] = useState<Record<string, any>>({});
  const [id, setId] = useState('');
  const [editorMode, setEditorMode] = useState<'create' | 'update'>('create');
  const { paginationConfig, savePageList, checkPageList } = usePagination();
  const [debugDrawVisible, setDebugDrawVisible] = useState(false);
  const [routeId, setRouteId] = useState<string>('');

  useEffect(() => {
    fetchLabelList().then(setLabelList);
  }, []);

  const rowSelection: any = {
    selectedRowKeys,
    onChange: (currentSelectKeys: string[]) => {
      setSelectedRowKeys(currentSelectKeys);
    },
    preserveSelectedRowKeys: true,
    selections: [Table.SELECTION_ALL, Table.SELECTION_INVERT, Table.SELECTION_NONE],
    defaultSelectedRowKeys: [1],
  };

  const handleTableActionSuccessResponse = (msgTip: string) => {
    notification.success({
      message: msgTip,
    });

    checkPageList(ref);
  };

  const { run: handlePublishOffline } = useThrottleFn(
    (rid: string, status: RouteModule.RouteStatus) => {
      setRouteId(rid);
      updateRouteStatus(rid, status)
        .then(() => {
          const actionName = status
            ? formatMessage({ id: 'page.route.publish' })
            : formatMessage({ id: 'page.route.offline' });
          handleTableActionSuccessResponse(
            `${actionName} ${formatMessage({
              id: 'menu.routes',
            })} ${formatMessage({ id: 'component.status.success' })}`,
          );
        })
        .finally(() => {
          setRouteId('');
        });
    },
  );

  const ListToolbar = () => {
    const tools = [
      {
        name: formatMessage({ id: 'page.route.pluginTemplateConfig' }),
        icon: <PlusOutlined />,
        onClick: () => {
          history.push('/plugin-template/list');
        },
      },
      {
        name: formatMessage({ id: 'component.global.data.editor' }),
        icon: <PlusOutlined />,
        onClick: () => {
          setVisible(true);
          setEditorMode('create');
          setRawData({});
        },
      },
      {
        name: formatMessage({ id: 'page.route.data_loader.import' }),
        icon: <ImportOutlined />,
        onClick: () => {
          setShowImportDrawer(true);
        },
      },
    ];

    return (
      <Dropdown
        overlay={
          <Menu>
            {tools.map((item) => (
              <Menu.Item key={item.name} onClick={item.onClick}>
                {item.icon}
                {item.name}
              </Menu.Item>
            ))}
          </Menu>
        }
      >
        <Button type="dashed">
          <DownOutlined /> {formatMessage({ id: 'menu.advanced-feature' })}
        </Button>
      </Dropdown>
    );
  };

  const RecordActionDropdown: React.FC<{ record: any }> = ({ record }) => {
    const tools: {
      name: string;
      onClick: () => void;
      icon?: ReactNode;
    }[] = [
      {
        name: formatMessage({ id: 'component.global.view' }),
        onClick: () => {
          setId(record.id);
          setRawData(omit(record, DELETE_FIELDS));
          setVisible(true);
          setEditorMode('update');
        },
      },
      {
        name: formatMessage({ id: 'component.global.duplicate' }),
        onClick: () => {
          history.push(`/routes/${record.id}/duplicate`);
        },
      },
      {
        name: formatMessage({ id: 'component.global.delete' }),
        onClick: () => {
          Modal.confirm({
            type: 'warning',
            title: formatMessage({ id: 'component.global.popconfirm.title.delete' }),
            content: (
              <>
                {formatMessage({ id: 'component.global.name' })} - {record.name}
                <br />
                ID - {record.id}
              </>
            ),
            onOk: () => {
              return remove(record.id!).then(() => {
                handleTableActionSuccessResponse(
                  `${formatMessage({ id: 'component.global.delete' })} ${formatMessage({
                    id: 'menu.routes',
                  })} ${formatMessage({ id: 'component.status.success' })}`,
                );
              });
            },
          });
        },
      },
    ];

    return (
      <Dropdown
        overlay={
          <Menu>
            {tools.map((item) => (
              <Menu.Item key={item.name} onClick={item.onClick}>
                {item.icon && item.icon}
                {item.name}
              </Menu.Item>
            ))}
          </Menu>
        }
      >
        <Button type="dashed">
          <DownOutlined />
          {formatMessage({ id: 'menu.more' })}
        </Button>
      </Dropdown>
    );
  };

  const tagStyle = {
    maxWidth: '200px',
    overflow: 'hidden',
    WhiteSpace: 'nowrap',
    textOverflow: 'ellipsis',
  };
  const columns: ProColumns<RouteModule.ResponseBody>[] = [
    {
      title: formatMessage({ id: 'component.global.name' }),
      dataIndex: 'name',
      width: 150,
    },
    {
      title: formatMessage({ id: 'component.global.id' }),
      dataIndex: 'id',
      width: 200,
    },
    {
      title: formatMessage({ id: 'page.route.host' }),
      dataIndex: 'host',
      width: 224,
      render: (_, record) => {
        const list = record.hosts || (record.host && [record.host]) || [];

        return list.map((item) => (
          <Tooltip key={item} placement="topLeft" title={item}>
            <Tag color="geekblue" style={tagStyle}>
              {item}
            </Tag>
          </Tooltip>
        ));
      },
    },
    {
      title: formatMessage({ id: 'page.route.path' }),
      dataIndex: 'uri',
      width: 224,
      render: (_, record) => {
        const list = record.uris || (record.uri && [record.uri]) || [];

        return list.map((item) => (
          <Tooltip key={item} placement="topLeft" title={item}>
            <Tag color="geekblue" style={tagStyle}>
              {item}
            </Tag>
          </Tooltip>
        ));
      },
    },
    {
      title: formatMessage({ id: 'component.global.description' }),
      dataIndex: 'desc',
      ellipsis: true,
      width: 200,
    },
    {
      title: formatMessage({ id: 'component.global.labels' }),
      dataIndex: 'labels',
      width: 240,
      render: (_, record) => {
        return Object.keys(record.labels || {})
          .filter((item) => item !== 'API_VERSION')
          .map((item) => (
            <Tag key={Math.random().toString(36).slice(2)}>
              {item}:{record.labels[item]}
            </Tag>
          ));
      },
      renderFormItem: (_, { type }) => {
        console.log(labelList);

        if (type === 'form') {
          return null;
        }

        return (
          <Select
            mode="tags"
            style={{ width: '100%' }}
            placeholder={formatMessage({ id: 'component.global.pleaseChoose' })}
            tagRender={(props) => {
              const { value, closable, onClose } = props;
              return (
                <Tag closable={closable} onClose={onClose} style={{ marginRight: 3 }}>
                  {value}
                </Tag>
              );
            }}
          >
            {Object.keys(labelList)
              .filter((item) => item !== 'API_VERSION')
              .map((key) => {
                return (
                  <OptGroup label={key} key={Math.random().toString(36).slice(2)}>
                    {(labelList[key] || []).map((value: string) => (
                      <Option key={Math.random().toString(36).slice(2)} value={`${key}:${value}`}>
                        {' '}
                        {value}{' '}
                      </Option>
                    ))}
                  </OptGroup>
                );
              })}
          </Select>
        );
      },
    },
    {
      title: formatMessage({ id: 'component.global.version' }),
      dataIndex: 'API_VERSION',
      width: 100,
      render: (_, record) => {
        return Object.keys(record.labels || {})
          .filter((item) => item === 'API_VERSION')
          .map((item) => record.labels[item]);
      },
      renderFormItem: (_, { type }) => {
        if (type === 'form') {
          return null;
        }

        return (
          <Select
            style={{ width: '100%' }}
            placeholder={formatMessage({ id: 'component.global.pleaseChoose' })}
            allowClear
          >
            {Object.keys(labelList)
              .filter((item) => item === 'API_VERSION')
              .map((key) => {
                return (
                  <OptGroup label={key} key={Math.random().toString(36).slice(2)}>
                    {(labelList[key] || []).map((value: string) => (
                      <Option key={Math.random().toString(36).slice(2)} value={`${key}:${value}`}>
                        {' '}
                        {value}{' '}
                      </Option>
                    ))}
                  </OptGroup>
                );
              })}
          </Select>
        );
      },
    },
    {
      title: formatMessage({ id: 'page.route.status' }),
      dataIndex: 'status',
      width: 100,
      render: (_, record) => (
        <>
          {record.status ? (
            <Tag color="green">{formatMessage({ id: 'page.route.published' })}</Tag>
          ) : (
            <Tag color="red">{formatMessage({ id: 'page.route.unpublished' })}</Tag>
          )}
        </>
      ),
      renderFormItem: (_, { type }) => {
        if (type === 'form') {
          return null;
        }

        return (
          <Select
            style={{ width: '100%' }}
            placeholder={`${formatMessage({ id: 'page.route.unpublished' })}/${formatMessage({
              id: 'page.route.published',
            })}`}
            allowClear
          >
            <Option key={RouteStatus.Offline} value={RouteStatus.Offline}>
              {formatMessage({ id: 'page.route.unpublished' })}
            </Option>
            <Option key={RouteStatus.Publish} value={RouteStatus.Publish}>
              {formatMessage({ id: 'page.route.published' })}
            </Option>
          </Select>
        );
      },
    },
    {
      title: formatMessage({ id: 'component.global.updateTime' }),
      dataIndex: 'update_time',
      hideInSearch: true,
      width: 200,
      render: (text) => timestampToLocaleString(text as number),
    },
    {
      title: formatMessage({ id: 'component.global.operation' }),
      valueType: 'option',
      fixed: 'right',
      hideInSearch: true,
      width: 240,
      render: (_, record) => (
        <>
          <Space align="baseline">
            {!record.status ? (
              <Button
                type="primary"
                onClick={() => {
                  handlePublishOffline(record.id, RouteStatus.Publish);
                }}
                loading={record.id === routeId}
              >
                {formatMessage({ id: 'page.route.publish' })}
              </Button>
            ) : null}
            {record.status ? (
              <Popconfirm
                title={formatMessage({ id: 'page.route.popconfirm.title.offline' })}
                onConfirm={() => {
                  handlePublishOffline(record.id, RouteStatus.Offline);
                }}
                okButtonProps={{
                  danger: true,
                }}
                okText={formatMessage({ id: 'component.global.confirm' })}
                cancelText={formatMessage({ id: 'component.global.cancel' })}
              >
                <Button
                  type="primary"
                  danger
                  disabled={Boolean(!record.status)}
                  loading={record.id === routeId}
                >
                  {formatMessage({ id: 'page.route.offline' })}
                </Button>
              </Popconfirm>
            ) : null}
            <Button type="primary" onClick={() => history.push(`/routes/${record.id}/edit`)}>
              {formatMessage({ id: 'component.global.edit' })}
            </Button>
            <RecordActionDropdown record={record} />
          </Space>
        </>
      ),
    },
    {
      title: formatMessage({ id: 'menu.plugin' }),
      dataIndex: 'plugins',
      width: 240,
      render: (_, record) => {
        const plugins = record.plugins || {};
        return Object.keys(plugins).length > 0
          ? Object.keys(plugins).map((key) => <Tag key={key}>{key}</Tag>)
          : '-';
      },
    },
  ];

  return (
    <PageHeaderWrapper
      title={formatMessage({ id: 'page.route.list' })}
      content={formatMessage({ id: 'page.route.list.description' })}
    >
      <ProTable<RouteModule.ResponseBody>
        actionRef={ref}
        rowKey="id"
        columns={columns}
        rowSelection={rowSelection}
        tableAlertRender={() => (
          <Space size={24}>
            <span>
              {formatMessage({ id: 'page.route.chosen' })} {selectedRowKeys.length}{' '}
              {formatMessage({ id: 'page.route.item' })}
            </span>
          </Space>
        )}
        tableAlertOptionRender={() => {
          return (
            <Space size={16}>
              <Button
                onClick={async () => {
                  await remove(selectedRowKeys).then(() => {
                    handleTableActionSuccessResponse(
                      `${formatMessage({ id: 'component.global.delete.routes.success' })}`,
                    );
                  });
                  ref.current?.reloadAndRest?.();
                }}
              >
                {formatMessage({ id: 'page.route.batchDeletion' })}
              </Button>
            </Space>
          );
        }}
        request={fetchList}
        pagination={{
          onChange: (page, pageSize?) => savePageList(page, pageSize),
          pageSize: paginationConfig.pageSize,
          current: paginationConfig.current,
        }}
        search={{
          searchText: formatMessage({ id: 'component.global.search' }),
          resetText: formatMessage({ id: 'component.global.reset' }),
        }}
        toolBarRender={() => [
          <Button type="primary" onClick={() => history.push(`/routes/create`)}>
            <PlusOutlined />
            {formatMessage({ id: 'component.global.create' })}
          </Button>,
          <ListToolbar />,
        ]}
        scroll={{ x: 1300 }}
      />
      <DebugDrawView
        visible={debugDrawVisible}
        onClose={() => {
          setDebugDrawVisible(false);
        }}
      />
      <RawDataEditor
        visible={visible}
        type="route"
        readonly={false}
        data={rawData}
        onClose={() => {
          setVisible(false);
        }}
        onSubmit={(data: any) => {
          (editorMode === 'create' ? create(data, 'RawData') : update(id, data, 'RawData')).then(
            () => {
              setVisible(false);
              ref.current?.reload();
            },
          );
        }}
      />
      {showImportDrawer && (
        <DataLoaderImport
          onClose={(finish) => {
            if (finish) checkPageList(ref);
            setShowImportDrawer(false);
          }}
        />
      )}
    </PageHeaderWrapper>
  );
};

export default Page;
