import { BaseEventOrig, Button, InputProps } from '@tarojs/components';
import Taro, { useLoad } from '@tarojs/taro';

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

import BlFormCell from '@/components/bl-form-cell';
import BlFormInput from '@/components/bl-form-input';
import BlFormItem from '@/components/bl-form-item';
import { BlFormRadio, BlFormRadioGroup } from '@/components/bl-form-radio';
import BlFormSelect from '@/components/bl-form-select';
import BlSalaryInput, { BlSalaryValue } from '@/components/bl-salary-input';
import { CityPickerPopup } from '@/components/city-picker';
import PageLoading from '@/components/page-loading';
import CompanyPublishJobBuy from '@/components/product-dialog/steps-ui/company-publish-job-buy';
import SafeBottomPadding from '@/components/safe-bottom-padding';
import { EventName, PageUrl } from '@/constants/app';
import { CertificationStatusType } from '@/constants/company';
import { CollectEventName } from '@/constants/event';
import { EMPLOY_TYPE_TITLE_MAP, EmployType, JOB_TYPE_SELECT_OPTIONS, JobType } from '@/constants/job';
import { ProductType } from '@/constants/product';
import useUserInfo from '@/hooks/use-user-info';
import store from '@/store';
import { cacheJobId } from '@/store/actions';
import { CreateJobInfo, JobDetails } from '@/types/job';
import { logWithPrefix } from '@/utils/common';
import { collectEvent } from '@/utils/event';
import {
  postCloseJob,
  postCreateJob,
  postUpdateJob,
  requestJobDetail,
  isFullTimePriceRequired,
  isPartTimePriceRequired,
  postPublishJob,
} from '@/utils/job';
import { getCityValues } from '@/utils/location';
import { requestProductBalance } from '@/utils/product';
import { getPageQuery, navigateBack, navigateTo } from '@/utils/route';
import Toast from '@/utils/toast';

import './index.less';
import { RESPONSE_ERROR_CODE } from '@/http/constant';

const PREFIX = 'page-job-publish';
const log = logWithPrefix(PREFIX);

const isInvalidCreateJobInfo = (data: CreateJobInfo) => {
  const {
    title,
    category,
    employType,
    provinceCode,
    cityCode,
    countyCode,
    address,
    jobDescription,
    lowPriceForFullTime,
    highPriceForFullTime,
    lowPriceForPartyTime,
    highPriceForPartyTime,
  } = data;
  if (!category) {
    return '请选择通告品类';
  }
  if (!title) {
    return '请选择通告标题';
  }
  if (!jobDescription) {
    return '请输入通告描述';
  }
  if (isFullTimePriceRequired(employType)) {
    if (!lowPriceForFullTime || !highPriceForFullTime) {
      return '薪资范围不能为空';
    }
    if (lowPriceForFullTime > highPriceForFullTime) {
      return '薪资最高值不能低于最低值';
    }
  }
  if (isPartTimePriceRequired(employType)) {
    if (!lowPriceForPartyTime || !highPriceForPartyTime) {
      return '薪资范围不能为空';
    }
    if (lowPriceForPartyTime > highPriceForPartyTime) {
      return '薪资最高值不能低于最低值';
    }
  }

  if (!provinceCode || !cityCode || !countyCode) {
    return '请输入工作地址';
  }
  if (!address) {
    return '请输入详细地址';
  }
};

export default function JobPublish() {
  const [loading, setLoading] = useState(false);
  const [isUpdate, setIsUpdate] = useState(false);
  const [job, setJob] = useState<JobDetails | null>(null);
  const [reason, setReason] = useState('');
  const [employType, setEmployType] = useState(EmployType.Full);
  const [category, setCategory] = useState<JobType>(JobType.Finery);
  const [title, setTitle] = useState('');
  const [describe, setDescribe] = useState('');
  const [salary, setSalary] = useState<BlSalaryValue>(['', '', '', ''] as unknown as BlSalaryValue);
  const [city, setCity] = useState<string[] | undefined>();
  const [showCityPicker, setShowCityPicker] = useState(false);
  const [address, setAddress] = useState('');
  const [showBuy, setShowBuy] = useState(false);
  const createdJobIdRef = useRef('');
  const userInfo = useUserInfo();

  const handleEmployTypeChange = useCallback((value: EmployType) => {
    setEmployType(value);
  }, []);

  const handleSelectCategory = useCallback((value: JobType) => {
    setCategory(value);
  }, []);

  const handleInputTitle = useCallback((e: BaseEventOrig<InputProps.inputEventDetail>) => {
    const value = e.detail.value || '';
    setTitle(value);
  }, []);

  const handleClickEditDescribe = useCallback(() => navigateTo(PageUrl.JobPublishDescribe, { describe }), [describe]);

  const handleSalaryChange = useCallback((value: BlSalaryValue) => {
    setSalary(value);
  }, []);

  const handleClickCity = useCallback(() => setShowCityPicker(true), []);

  const handleConfirmCityPicker = useCallback((areaValues: string[]) => {
    log('handleConfirmCityPicker', areaValues);
    setShowCityPicker(false);
    setCity(areaValues);
    setAddress('');
  }, []);

  const handleInputAddress = useCallback((e: BaseEventOrig<InputProps.inputEventDetail>) => {
    const value = e.detail.value || '';
    setAddress(value);
  }, []);

  const refreshJobPublishList = useCallback(() => {
    Taro.eventCenter.trigger(EventName.COMPANY_JOB_PUBLISH_CHANGED);
    setTimeout(() => {
      Taro.eventCenter.trigger(EventName.COMPANY_JOB_PUBLISH_CHANGED);
    }, 300);
  }, []);

  const handleClose = useCallback(async () => {
    if (!job) {
      Toast.error('数据出错请重试');
      return;
    }
    try {
      Taro.showLoading();
      await postCloseJob(job.id);
      refreshJobPublishList();
      navigateBack();
    } catch (e) {
      console.error('submit error', e);
      Toast.error('关闭失败请重试');
      collectEvent(CollectEventName.CLOSE_JOB_FAILED, e);
    } finally {
      Taro.hideLoading();
    }
  }, [job, refreshJobPublishList]);

  const getCreateJobInfo = useCallback((): [CreateJobInfo, string[]] => {
    const cityCodes = city || [];
    const data: CreateJobInfo = {
      title,
      employType,
      category: category!,
      jobDescription: describe,
      provinceCode: cityCodes[0],
      cityCode: cityCodes[1],
      countyCode: cityCodes[2],
      lowPriceForFullTime: !isFullTimePriceRequired(employType) ? 0 : salary[0] * 1000,
      highPriceForFullTime: !isFullTimePriceRequired(employType) ? 0 : salary[1] * 1000,
      lowPriceForPartyTime: !isPartTimePriceRequired(employType) ? 0 : salary[2],
      highPriceForPartyTime: !isPartTimePriceRequired(employType) ? 0 : salary[3],
      address: address,
    };
    return [data, cityCodes];
  }, [address, category, city, describe, employType, salary, title]);

  const handleSubmit = useCallback(async () => {
    const [data, cityCodes] = getCreateJobInfo();
    const errMsg = isInvalidCreateJobInfo(data);
    if (errMsg) {
      Toast.info(errMsg);
      return;
    }
    try {
      Taro.showLoading();
      // 将省市区拼到最前面
      const cityValues = getCityValues(cityCodes);
      if (!data.address.startsWith(cityValues)) {
        data.address = `${cityValues}${data.address}`;
      }
      const isUpdateJob = isUpdate && job;
      if (isUpdateJob) {
        data.jobId = job!.id;
        await postUpdateJob(data);
        Taro.eventCenter.trigger(EventName.JOB_UPDATE, job!.id);
      } else {
        const jobId = await postCreateJob(data);
        createdJobIdRef.current = jobId;
        refreshJobPublishList();

        if (userInfo.bossAuthStatus !== CertificationStatusType.Success) {
          // 去认证
          store.dispatch(cacheJobId(jobId));
          navigateTo(PageUrl.CertificationStart);
          Taro.hideLoading();
          return;
        }

        const [time] = await requestProductBalance(ProductType.CompanyPublishJob);
        if (time <= 0) {
          // 付钱
          setShowBuy(true);
          Taro.hideLoading();
          return;
        }

        await postPublishJob(jobId);
      }
      refreshJobPublishList();

      await Toast.success(isUpdateJob ? '更新成功' : '创建并发布成功', 1500, true);
      navigateBack();
    } catch (e) {
      createdJobIdRef.current = '';
      console.error('submit error', e.errorCode, e.errorMsg);
      console.dir(e);
      if (e.errorCode === RESPONSE_ERROR_CODE.JOB_EXIST_ONE_PUBLISHED) {
        Toast.info(e.errorMsg || e.errorCode, 3000);
      } else {
        Toast.error('审核失败请重试');
      }
      collectEvent(CollectEventName.PUBLISH_JOB_FAILED, e);
    } finally {
      Taro.hideLoading();
    }
  }, [getCreateJobInfo, isUpdate, job, userInfo.bossAuthStatus, refreshJobPublishList]);

  const handleNext = useCallback(async () => {
    Taro.showLoading();
    try {
      await postPublishJob(createdJobIdRef.current);
      refreshJobPublishList();
      await Toast.success('发布成功', 1500, true);
      navigateBack();
    } catch (e) {
      console.error('submit error', e.errorCode, e.errorMsg);
      console.dir(e);
      if (e.errorCode === RESPONSE_ERROR_CODE.JOB_EXIST_ONE_PUBLISHED) {
        Toast.info(e.errorMsg || e.errorCode, 3000);
      } else {
        Toast.error('审核失败请重试');
      }
      collectEvent(CollectEventName.PUBLISH_JOB_FAILED, e);
    } finally {
      Taro.hideLoading();
    }
  }, [refreshJobPublishList]);

  const handleClosePublishJob = useCallback(() => {
    setShowBuy(false);
    navigateBack(-1);
  }, []);

  useEffect(() => {
    const callback = (d: string) => setDescribe(d);
    Taro.eventCenter.on(EventName.EDIT_JOB_DESCRIBE, callback);
    return () => {
      Taro.eventCenter.off(EventName.EDIT_JOB_DESCRIBE, callback);
    };
  }, []);

  useLoad(async () => {
    const query = getPageQuery<{ jobId: string }>();
    const jobId = query?.jobId;
    if (!jobId) {
      return;
    }
    try {
      setLoading(true);
      setIsUpdate(true);
      const details = await requestJobDetail(jobId);
      setJob(details);
      details.title && setTitle(details.title);
      details.employType && setEmployType(details.employType);
      details.category && setCategory(details.category);
      details.jobDescription && setDescribe(details.jobDescription);
      details.jobLocation.provinceCode &&
        details.jobLocation.cityCode &&
        details.jobLocation.countyCode &&
        setCity([details.jobLocation.provinceCode, details.jobLocation.cityCode, details.jobLocation.countyCode]);
      details.lowPriceForFullTime &&
        details.highPriceForFullTime &&
        details.lowPriceForPartyTime &&
        details.highPriceForPartyTime &&
        setSalary([
          details.lowPriceForFullTime / 1000,
          details.highPriceForFullTime / 1000,
          details.lowPriceForPartyTime,
          details.highPriceForPartyTime,
        ]);
      details.jobLocation.address && setAddress(details.jobLocation.address);
      details.verifyFailReason && setReason(details.verifyFailReason);
    } catch (e) {
      console.error(e);
      Toast.error('出错了，请重试');
    } finally {
      setLoading(false);
    }
  });

  if (loading) {
    return <PageLoading />;
  }

  return (
    <div className={PREFIX}>
      {reason && <div className={`${PREFIX}__reason`}>{reason}</div>}
      <BlFormItem title="通告标题" subTitle="不能填写微信、电话等联系方式">
        <BlFormInput
          value={title}
          maxlength={20}
          placeholder="如“招聘女装主播”"
          onInput={handleInputTitle}
          maxLengthTips
        />
      </BlFormItem>
      <BlFormItem title="工作类型" subTitle={false}>
        <BlFormRadioGroup direction="horizontal" value={employType} onChange={handleEmployTypeChange}>
          <BlFormRadio name={EmployType.Full} text={EMPLOY_TYPE_TITLE_MAP[EmployType.Full]} value={employType} />
          <BlFormRadio name={EmployType.Part} text={EMPLOY_TYPE_TITLE_MAP[EmployType.Part]} value={employType} />
          <BlFormRadio name={EmployType.All} text={EMPLOY_TYPE_TITLE_MAP[EmployType.All]} value={employType} />
        </BlFormRadioGroup>
      </BlFormItem>
      <BlFormItem title="品类" subTitle={false}>
        <BlFormSelect title="品类" value={category} options={JOB_TYPE_SELECT_OPTIONS} onSelect={handleSelectCategory} />
      </BlFormItem>
      <BlFormItem title="薪资范围" subTitle={false} dynamicHeight>
        <BlSalaryInput value={salary} employType={employType} onChange={handleSalaryChange} />
      </BlFormItem>
      <BlFormItem title="通告描述" subTitle={false}>
        <BlFormCell text={describe} placeholder="介绍工作内容、通告要求、加分项" onClick={handleClickEditDescribe} />
      </BlFormItem>
      <BlFormItem title="工作城市" subTitle={false}>
        <BlFormCell text={getCityValues(city, '-')} placeholder="工作所在省-城-区" onClick={handleClickCity} />
      </BlFormItem>
      <BlFormItem title="详细地址" subTitle={false}>
        <BlFormInput value={address} placeholder="请填写详细地址" onInput={handleInputAddress} />
      </BlFormItem>
      <SafeBottomPadding />
      <div className={`${PREFIX}__footer`}>
        <div className={`${PREFIX}__footer__tips`}>注：通告标题和工作城市发布后不可修改</div>
        <div className={`${PREFIX}__footer__buttons`}>
          {!isUpdate && (
            <Button className={`${PREFIX}__footer__button`} onClick={handleSubmit}>
              创建并发布
            </Button>
          )}
          {isUpdate && (
            <>
              <Button className={classNames(`${PREFIX}__footer__button`, 'lowLight')} onClick={handleClose}>
                关闭
              </Button>
              <Button className={`${PREFIX}__footer__button`} onClick={handleSubmit}>
                更新
              </Button>
            </>
          )}
        </div>
        <SafeBottomPadding />
      </div>
      <div>
        <CityPickerPopup
          areaValues={city}
          open={showCityPicker}
          onConfirm={handleConfirmCityPicker}
          onCancel={() => setShowCityPicker(false)}
        />
        <Dialog open={showBuy} onClose={handleClosePublishJob}>
          <Dialog.Content>
            <CompanyPublishJobBuy onNext={handleNext} />
          </Dialog.Content>
        </Dialog>
      </div>
    </div>
  );
}
