import { List, PullRefresh } from '@taroify/core';
import classNames from 'classnames';
import { useCallback, useEffect, useRef, useState } from 'react';

import JobCard from '@/components/job-card';
import ListPlaceholder from '@/components/list-placeholder';
import { UserJobType } from '@/constants/job';
import { JobInfo, GetUserJobRequest } from '@/types/job';
import { logWithPrefix } from '@/utils/common';
import { requestUserJobList as requestData } from '@/utils/job';

import './index.less';

interface IRequestProps extends Partial<GetUserJobRequest> {
  type: number;
}

export interface IJobListProps extends IRequestProps {
  refreshDisabled?: boolean;
  listHeight?: number;
  className?: string;
}

const FIRST_PAGE = 0;
const PAGE_SIZE = 40;
const PREFIX = 'user-job-list';
const log = logWithPrefix(PREFIX);

function UserJobList(props: IJobListProps) {
  const { className, listHeight, refreshDisabled, type = UserJobType.MyDeclared, keyWord } = props;
  const [refreshing, setRefreshing] = useState(false);
  const [hasMore, setHasMore] = useState(true);
  const [loadingMore, setLoadingMore] = useState(false);
  const [loadMoreError, setLoadMoreError] = useState(false);
  const [dataMap, setDataMap] = useState<Map<string, JobInfo[]>>(new Map());
  const currentPage = useRef<number>(FIRST_PAGE);
  const requestProps = useRef<IRequestProps>({ type });

  const dateGroups = [...dataMap.keys()].sort().reverse();

  const handleRefresh = useCallback(async () => {
    log('start pull refresh');
    try {
      setRefreshing(true);
      setLoadMoreError(false);
      const { page, hasMore: more, dataMap: map } = await requestData({ ...requestProps.current, page: 1 });
      setHasMore(more);
      setDataMap(map);
      currentPage.current = page;
      log('pull refresh success');
    } catch (e) {
      setDataMap(new Map());
      setHasMore(false);
      setLoadMoreError(true);
      currentPage.current = FIRST_PAGE;
      log('pull refresh failed');
    } finally {
      setRefreshing(false);
    }
  }, []);

  const handleLoadMore = useCallback(async () => {
    log('start load more', hasMore);
    if (!hasMore) {
      return;
    }
    setLoadMoreError(false);
    setLoadingMore(true);
    try {
      const {
        page,
        hasMore: more,
        dataMap: map,
      } = await requestData({ ...requestProps.current, page: currentPage.current + 1 });
      const newMap = new Map(dataMap);
      for (const date of map.keys()) {
        const newJobs = map.get(date) || [];
        if (newMap.has(date)) {
          const jobs = newMap.get(date);
          jobs?.push(...newJobs);
        } else {
          newMap.set(date, newJobs);
        }
      }
      setDataMap(newMap);
      setHasMore(more);
      currentPage.current = page;
      log('load more success');
    } catch (e) {
      setLoadMoreError(true);
      log('load more failed');
    } finally {
      setLoadingMore(false);
    }
  }, [dataMap, currentPage, hasMore]);

  useEffect(() => {
    log('request params changed');
    requestProps.current = { type, keyWord, pageSize: PAGE_SIZE };
  }, [type, keyWord]);

  // 初始化数据&配置变更后刷新数据
  useEffect(() => {
    const refresh = async () => {
      log('props changed, start refresh list data');
      try {
        setDataMap(new Map());
        setLoadingMore(true);
        setLoadMoreError(false);
        const { page, hasMore: more, dataMap: map } = await requestData({ ...requestProps.current, page: 1 });
        setHasMore(more);
        setDataMap(map);
        currentPage.current = page;
      } catch (e) {
        setDataMap(new Map());
        setHasMore(false);
        setLoadMoreError(true);
        currentPage.current = FIRST_PAGE;
      } finally {
        log('props changed, refresh list data end');
        setLoadingMore(false);
      }
    };
    refresh();
  }, [type, keyWord]);

  return (
    <PullRefresh
      className={classNames(`${PREFIX}__pull-refresh`, className)}
      loading={refreshing}
      onRefresh={handleRefresh}
      disabled={refreshDisabled}
    >
      <List
        hasMore={hasMore}
        onLoad={handleLoadMore}
        loading={loadingMore || refreshing}
        disabled={loadMoreError}
        fixedHeight={typeof listHeight !== 'undefined'}
        style={listHeight ? { height: `${listHeight}px` } : undefined}
      >
        {dateGroups.map(date => {
          const jobs = dataMap.get(date) || [];
          return (
            <>
              <div className={`${PREFIX}__list-date-group`} key={date}>
                {date}
              </div>
              {jobs.map((item, index) => (
                <JobCard
                  data={item}
                  key={item.id}
                  className={classNames(`${PREFIX}__list-card`, { last: index === jobs.length - 1 })}
                />
              ))}
            </>
          );
        })}
        <ListPlaceholder hasMore={hasMore} loadingMore={loadingMore} loadMoreError={loadMoreError} />
      </List>
    </PullRefresh>
  );
}

export default UserJobList;
