import { Button } from '@tarojs/components';
import Taro, { UploadTask, useDidHide, useLoad, useUnload } from '@tarojs/taro';

import { isEqual } from 'lodash-es';
import { useCallback, useEffect, useRef, useState } from 'react';

import MaterialVideoCard from '@/components/material-video-card';
import SafeBottomPadding from '@/components/safe-bottom-padding';
import { EventName, OpenSource, PageUrl } from '@/constants/app';
import { CollectEventName, ReportEventId } from '@/constants/event';
import { MaterialVideoInfo } from '@/types/material';
import { logWithPrefix } from '@/utils/common';
import { collectEvent, reportEvent } from '@/utils/event';
import { chooseMedia, postVideos, requestVideoList } from '@/utils/material';
import { getPageQuery, navigateBack, navigateTo } from '@/utils/route';
import Toast from '@/utils/toast';
import { uploadVideo } from '@/utils/video';

import './index.less';

// 限制 500M
const MAX_FILE_SIZE_LIMIT = 1024 * 1024 * 1000;
const PREFIX = 'page-material-upload-video';
const log = logWithPrefix(PREFIX);
const TEMP_DATA: MaterialVideoInfo = { url: '', coverUrl: '', title: '', type: 'image', isDefault: false };

export default function MaterialUploadVideo() {
  const [source, setSource] = useState(OpenSource.None);
  const [videoList, setVideoList] = useState<MaterialVideoInfo[]>([]);
  const saveRef = useRef<(videos: MaterialVideoInfo[]) => Promise<void>>();
  const lastSaveVideosRef = useRef<MaterialVideoInfo[]>([]);

  const initVideoList = useCallback(async () => {
    try {
      const res = await requestVideoList();
      lastSaveVideosRef.current = res;
      setVideoList(res);
    } catch (e) {
      console.error(e);
      Toast.error('加载失败请重试');
    }
  }, []);

  const handleClickDelete = useCallback(
    (video: MaterialVideoInfo) => {
      log('handleClickDelete', video);
      const newVideoList = videoList.filter(v => v.coverUrl !== video.coverUrl);
      setVideoList(newVideoList);
    },
    [videoList]
  );

  const handleDefaultChange = useCallback(
    (video: MaterialVideoInfo) => {
      log('handleDefaultChange', video);
      const newVideoList = videoList.map(v => ({ ...v, isDefault: v.coverUrl === video.coverUrl }));
      setVideoList(newVideoList);
    },
    [videoList]
  );

  const handleTitleChange = useCallback(
    (video: MaterialVideoInfo, newTitle: string) => {
      // log('handleTitleChange', video, newTitle);
      const newVideoList = [...videoList];
      const index = newVideoList.findIndex(v => v.coverUrl === video.coverUrl);
      if (index < 0) {
        return;
      }
      newVideoList.splice(index, 1, { ...video, title: newTitle });
      setVideoList(newVideoList);
    },
    [videoList]
  );

  const handleClickUpload = useCallback(async () => {
    log('click upload');
    let showLoading = false;
    try {
      reportEvent(ReportEventId.CLICK_UPLOAD_VIDEO);
      const media = await chooseMedia();
      if (!media) {
        return;
      }
      const { type, tempFiles } = media;
      log('upload result', type, tempFiles);
      const tempFile = tempFiles[0];
      if (!tempFile) {
        throw new Error('tempFile is not exist');
      }
      if (tempFile.size > MAX_FILE_SIZE_LIMIT) {
        Toast.info('视频超过1000m，请更换', 3000);
        collectEvent(CollectEventName.VIDEO_EXCEEDING_LIMITS);
        return;
      }
      showLoading = true;
      Taro.showLoading({ title: '准备上传' });
      const onProgress: UploadTask.OnProgressUpdateCallback = res => {
        log('上传视频进度', res.progress, '总长度', res.totalBytesExpectedToSend, '已上传的长度', res.totalBytesSent);
        Taro.showLoading({ title: `上传${res.progress}%` });
      };
      const { url, coverUrl } = await uploadVideo(tempFile.tempFilePath, tempFile.fileType, onProgress);
      const newVideo: MaterialVideoInfo = {
        title: '',
        isDefault: false,
        url: url,
        coverUrl: coverUrl,
        type: tempFile.fileType === 'video' ? 'video' : 'image',
      };
      setVideoList([...videoList, newVideo]);
    } catch (e) {
      console.error('upload fail', e);
      Toast.error('上传失败');
      collectEvent(CollectEventName.UPLOAD_VIDEO_FAILED, e);
    } finally {
      showLoading && Taro.hideLoading();
    }
  }, [videoList]);

  const handleClickSubmit = useCallback(async () => {
    log('handleClickSubmit', videoList);
    reportEvent(ReportEventId.CLICK_SAVE_VIDEOS);
    if (videoList.length < 2) {
      Toast.info('请至少上传 2 个录屏');
      return;
    }
    try {
      Taro.showLoading();
      await saveRef.current?.(videoList);
      Taro.eventCenter.trigger(EventName.CREATE_PROFILE);
      if (source === OpenSource.None) {
        navigateTo(PageUrl.MaterialCreateProfile);
      } else {
        navigateBack();
      }
    } catch (e) {
      Toast.error('保存失败请重试');
      collectEvent(CollectEventName.SAVE_VIDEO_LIST_FAILED, e);
    } finally {
      Taro.hideLoading();
    }
  }, [videoList, source]);

  useEffect(() => {
    saveRef.current = async (videos: MaterialVideoInfo[]) => {
      if (!videos.length) {
        log('长度为空不保存');
        return;
      }
      if (isEqual(lastSaveVideosRef.current, videos)) {
        log('没变化不保存');
        return;
      }
      lastSaveVideosRef.current = videos;
      await postVideos(videos);
    };
  }, []);

  useLoad(() => {
    const query = getPageQuery<{ source: OpenSource }>();
    log('query', query);
    const { source: openSource } = query;
    openSource && setSource(openSource);
    initVideoList();
  });

  useDidHide(() => {
    log('didHide', videoList);
    saveRef.current?.(videoList);
  });

  useUnload(() => {
    log('unload', videoList);
    saveRef.current?.(videoList);
  });

  return (
    <div className={PREFIX}>
      <div className={`${PREFIX}__header`}>
        <div className={`${PREFIX}__header-title`}>上传录屏更易获得企业青睐</div>
        <div className={`${PREFIX}__header-tips`}>录屏是企业最关注的资料，建议提供多个风格和品类</div>
      </div>
      <div className={`${PREFIX}__video-list`}>
        <div className={`${PREFIX}__hint`}>注：请勿乱传，也不要上传简历，会被封号</div>
        {videoList.map(video => (
          <MaterialVideoCard
            key={video.coverUrl}
            videoInfo={video}
            onClickDelete={() => handleClickDelete(video)}
            onClickSetDefault={() => handleDefaultChange(video)}
            onTitleChange={(newTitle: string) => handleTitleChange(video, newTitle)}
          />
        ))}
        {videoList.length < 10 && <MaterialVideoCard videoInfo={TEMP_DATA} onClickUpload={handleClickUpload} isTemp />}
      </div>
      <SafeBottomPadding />
      <div className={`${PREFIX}__footer`}>
        <Button className={`${PREFIX}__submit-btn`} onClick={handleClickSubmit}>
          {source === OpenSource.None ? '下一步' : '保存'}
        </Button>
        <SafeBottomPadding />
      </div>
    </div>
  );
}
