import React, { useEffect, useReducer, useState } from "react";
import {
  Table,
  Justify,
  Button,
  SearchBox,
  Card,
  Layout,
  Bubble,
  Icon,
} from "@tencent/tea-component";

const { Body, Content } = Layout;
const { pageable, autotip, sortable, filterable } = Table.addons;

type ProductQuery = {
  skip: number;
  take: number;
  where?: object;
  select?: object;
  include?: object;
  orderBy?: object;
  distinct?: object;
}
type FindManyResult<T> = {
  data: T[];
  meta: {
    take: number;
    itemCount: number;
    pageCount: number;
    hasPreviousPage: Boolean;
    hasNextPage: Boolean;
  }
}
type Product = {
  id: number;
  createdAt?: string;
  updatedAt?: string;
  name?: string;
  description?: string;
  price?: number;
  sku?: string;
  published?: boolean;
}
type FethState<T> = {
  isLoading: Boolean;
  isError: Boolean;
  data: T | null,
};
type ReducerAction<T> = {
  type: 'FETCH_INIT' | 'FETCH_SUCCESS' | 'FETCH_FAILURE';
  payload?: T;
};
const dataFetchReducer = (state : any, action: any) => {
  switch (action.type) {
    case 'FETCH_INIT':
      return {
        ...state,
        isLoading: true,
        isError: false,
        data: null,
      };
    case 'FETCH_SUCCESS':
      return {
        ...state,
        isLoading: false,
        isError: false,
        data: action.payload,
      };
    case 'FETCH_FAILURE':
      return {
        ...state,
        isLoading: false,
        isError: true,
        data: null,
      };
    default:
      throw new Error();
  }
};
const useTableData = (initialUrl: string, initialPostData: ProductQuery, initialData: FindManyResult<Product> | null) => {
  const [url, setUrl] = useState(initialUrl);
  const [postData, setPostData] = useState(initialPostData);

  const [state, dispatch] = useReducer(dataFetchReducer, {
    isLoading: false,
    isError: false,
    data: initialData,
  });

  useEffect(() => {
    let didCancel = false;

    const fetchData = async () => {
      dispatch({ type: 'FETCH_INIT' });

      try {
        const response = await fetch(url, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json;charset=utf-8'
          }, 
          body: JSON.stringify(postData) 
        });
        if(!response.ok){
          throw new Error(`response error ${response.status},${response.statusText}`);
        }

        if (!didCancel) {
          dispatch({ type: 'FETCH_SUCCESS', payload: await response.json() });
        }
      } catch (error) {
        if (!didCancel) {
          dispatch({ type: 'FETCH_FAILURE' });
        }
      }
    };

    fetchData();

    return () => {
      didCancel = true;
    };
  }, [url, postData]);

  return [state, setPostData, setUrl];
};
const INITIAL_POST_DATA = {
  "skip": 0,
  "take": 10,
};
const ALL_VALUE = "__ALL__";
export default function Product() {
  const [searchInput, setSearchInput] = useState('');
  const [keyword, setKeyword] = useState("");
  const [sorts, setSorts] = useState([]);
  const [filter, setFilter] : [any, any] = useState({});
  const [{isLoading, isError, data}, setPostData, setUrl] = useTableData(
    'http://localhost:8000/product/findMany',
    INITIAL_POST_DATA,
    null,
  );

  let records = [];
  if(data) {
    records = data.data;
  }

  let recordCount = 0;
  if(data && data.meta){
    recordCount = data.meta.itemCount;
  }

  return (
    <Layout>
      <Body>
        <Content>
          <Content.Body>
            <Table.ActionPanel>
              <Justify
                left={
                  <>
                    <Button type="primary">新建</Button>
                    <Button>开机</Button>
                  </>
                }
                right={
                  <>
                    <SearchBox 
                      disabled={isLoading}
                      value={searchInput}
                      onChange={keywordInput => setSearchInput(keywordInput)}
                      onSearch={kw => {
                        if(kw === keyword && keyword === ''){
                          return ;
                        }
                        setKeyword(kw || '');
                        setPostData({...INITIAL_POST_DATA, where: {
                          OR: [
                            { id: {equals: Number(kw) || -1} },
                            { name: {contains: kw} },
                            { sku: {contains: kw} },
                          ]}
                        });
                      }}
                      onClear={() => {
                        setKeyword('');
                        setPostData({...INITIAL_POST_DATA});
                      }}
                      placeholder="搜索ID/产品名/SKU"
                    />
                    <Button icon="setting" />
                    <Button icon="refresh" onClick={() => {setPostData((prev: any) => ({...prev}))}}/>
                    <Button icon="download" />
                  </>
                }
              />
            </Table.ActionPanel>
            <Card>
              <Table
                verticalTop
                records={records}
                recordKey="id"
                columns={[
                  {
                    key: "id",
                    header: "ID"
                  },
                  {
                    key: "name",
                    header: "产品名",
                  },
                  {
                    key: "price",
                    header: "价格",
                  },
                  {
                    key: "sku",
                    header: "SKU",
                  },
                  {
                    key: "published",
                    header: () => (
                      <>
                        状态
                        <Bubble content="状态描述">
                          <Icon type="info" />
                        </Bubble>
                      </>
                    ),
                    width: 100,
                    render: (row : Product) => {
                      if (row.published) {
                        return <span style={{ color: "green" }}>已发布</span>;
                      }
                      return <span style={{ color: "red" }}>未发布</span>;
                    },
                  },
                  {
                    key: "updatedAt",
                    header: "更新时间",
                  },
                ]}
                addons={[
                  pageable({
                    recordCount,
                    onPagingChange: (query) => {setPostData((prev: any) => ({
                      ...prev,
                      take: query.pageSize || 10,
                      skip: ((query.pageIndex || 1) - 1) * (query.pageSize || 10),
                    }))},
                  }),
                  autotip({
                    isLoading: isLoading,
                    isError: isError,
                    isFound: Boolean(keyword),
                    onClear: () => {
                      setKeyword('');
                      setSearchInput('');
                      setPostData({...INITIAL_POST_DATA})
                    },
                    onRetry: () => setPostData((prev:any) => ({...prev})),
                    foundKeyword: keyword,
                  }),
                  sortable({
                    columns: [
                      "id",
                      "name",
                      {
                        key: "price",
                        prefer: "desc",
                      },
                    ],
                    value: sorts,
                    onChange: (value:any) => {
                      setSorts(value);
                      setPostData((prev:any) => ({
                        ...prev, 
                        orderBy: value.map((item: any) => ({
                          [item.by]: item.order,
                        })),
                      }));
                    }
                  }),

                  filterable({
                    type: "single",
                    column: "published",
                    value: filter.published,
                    // searchable: true,
                    onChange: value => {
                      setFilter((prev: any) => {
                        return {...prev, published: value}
                      });
                      
                      setPostData((prev:any) => {
                        if(!prev.where){
                          prev.where = {};
                        }
                        if(value === ALL_VALUE){
                          delete prev.where.published;
                        } else {
                          prev.where.published = {equals: JSON.parse(value)};
                        }
                        return {...prev};
                      });
                    },
                    // 增加 "全部" 选项
                    all: {
                      value: ALL_VALUE,
                      text: "全部",
                    },
                    // 选项列表
                    options: [
                      { value: "true", text: "已发布" },
                      { value: "false", text: "未发布" },
                    ],
                  }),
                ]}
              />
            </Card>
          </Content.Body>
        </Content>
      </Body>
    </Layout>
  );
}
