/*
 * 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 { useState, useRef, useEffect, useLayoutEffect } from 'react';
import { Modal, Form, Button, FormCheck } from 'react-bootstrap';
import { useTranslation } from 'react-i18next';

import ReactDOM from 'react-dom/client';

import { useToast } from '@/hooks';
import { useCaptchaPlugin } from '@/utils/pluginKit';
import type * as Type from '@/common/interface';
import {
  reportList,
  postReport,
  closeQuestion,
  putReport,
  putFlagReviewAction,
} from '@/services';

interface Params {
  isBackend?: boolean;
  type: Type.ReportType;
  id: string;
  title?: string;
  action: Type.ReportAction;
  source?: string;
  content?: string;
  reportType?: any;
}

const useReportModal = (callback?: () => void) => {
  const { t } = useTranslation('translation', { keyPrefix: 'report_modal' });
  const toast = useToast();
  const [params, setParams] = useState<Params | null>(null);
  const [isInvalid, setInvalidState] = useState(false);
  const [reportType, setReportType] = useState({
    type: -1,
    haveContent: false,
  });
  const rootRef = useRef<{ root: ReactDOM.Root | null }>({
    root: null,
  });

  const [content, setContent] = useState({
    value: '',
    isInvalid: false,
    errorMsg: '',
  });
  const [show, setShow] = useState(false);
  const [list, setList] = useState<any[]>([]);

  const rCaptcha = useCaptchaPlugin('report');

  useEffect(() => {
    const div = document.createElement('div');
    rootRef.current.root = ReactDOM.createRoot(div);
  }, []);
  const getList = ({ type, action, isBackend, ...otherParams }: Params) => {
    // @ts-ignore
    reportList({
      type,
      action,
      isBackend,
    }).then((res) => {
      setList(res);
      if (otherParams.reportType) {
        const findType = res.find(
          (v) => v.reason_type === otherParams.reportType,
        );
        if (findType) {
          setReportType({
            type: findType.reason_type,
            haveContent: Boolean(findType.content_type),
          });

          setContent({
            value: otherParams.content || '',
            isInvalid: false,
            errorMsg: '',
          });
        }
      }
      setShow(true);
    });
  };
  const asyncCallback = () => {
    setTimeout(() => {
      callback?.();
    });
  };
  const handleRadio = (val) => {
    setInvalidState(false);
    setContent({
      value:
        val.reason_type === params?.reportType ? String(params?.content) : '',
      isInvalid: false,
      errorMsg: '',
    });
    setReportType({
      type: val.reason_type,
      haveContent: Boolean(val.content_type),
    });
  };

  const onClose = () => {
    setReportType({
      type: -1,
      haveContent: false,
    });
    setContent({
      value: '',
      isInvalid: false,
      errorMsg: '',
    });
    setShow(false);
  };

  const checkValidate = () => {
    if (reportType.haveContent && !content.value) {
      setContent({
        value: content.value,
        isInvalid: true,
        errorMsg: t('remark.empty'),
      });
      return false;
    }

    if (reportType.type === 60) {
      // a duplicate
      let url: URL | undefined;
      try {
        url = new URL(content.value);
      } catch {
        setContent({
          value: content.value,
          isInvalid: true,
          errorMsg: t('msg.not_a_url'),
        });
      }
      if (!url) return false;

      if (url.origin !== window.location.origin) {
        setContent({
          value: content.value,
          isInvalid: true,
          errorMsg: t('msg.url_not_match'),
        });
        return false;
      }
    }

    return true;
  };

  const submitReport = (data) => {
    const flagReq = {
      source: data.type,
      report_type: reportType.type,
      object_id: data.id,
      content: content.value,
      captcha_code: undefined,
      captcha_id: undefined,
    };
    rCaptcha?.resolveCaptchaReq(flagReq);

    postReport(flagReq)
      .then(async () => {
        await rCaptcha?.close();
        toast.onShow({
          msg: t('flag_success', { keyPrefix: 'toast' }),
          variant: 'warning',
        });
        onClose();
        asyncCallback();
      })
      .catch((ex) => {
        if (ex.isError) {
          rCaptcha?.handleCaptchaError(ex.list);
        }
      });
  };

  const handleSubmit = () => {
    if (!params) {
      return;
    }
    if (reportType.type === -1) {
      setInvalidState(true);
      return;
    }

    if (!checkValidate()) {
      return;
    }

    if (params.type === 'question' && params.action === 'close') {
      if (params?.source === 'review') {
        putFlagReviewAction({
          flag_id: params.id,
          operation_type: 'close_post',
          close_type: reportType.type,
          close_msg: content.value,
        }).then(() => {
          onClose();
          asyncCallback();
        });
        return;
      }
      closeQuestion({
        id: params.id,
        close_type: reportType.type,
        close_msg: content.value,
      }).then(() => {
        onClose();
        asyncCallback();
      });
      return;
    }
    if (!params.isBackend && params.action === 'flag') {
      if (!rCaptcha) {
        submitReport(params);
        return;
      }
      rCaptcha.check(() => {
        submitReport(params);
      });
    }

    if (params.isBackend && params.action === 'review') {
      putReport({
        action: params.type,
        flagged_content: content.value,
        flagged_type: reportType.type,
        id: params.id,
      }).then(() => {
        onClose();
        asyncCallback();
      });
    }
  };

  const onShow = (obj: Params) => {
    setParams(obj);
    getList(obj);
  };
  let title = '';
  if (typeof params === 'object' && params) {
    title = params.title || t(`${params.action}_title`);
    if (params.action === 'review') {
      title = t(`${params.action}_${params.type}_title`);
    }
  }
  useLayoutEffect(() => {
    rootRef.current.root?.render(
      <Modal show={show} onHide={onClose}>
        <Modal.Header closeButton>
          <Modal.Title as="h5">{title}</Modal.Title>
        </Modal.Header>
        <Modal.Body>
          <Form>
            {list.map((item) => {
              return (
                <div key={item?.reason_type}>
                  <Form.Group
                    controlId={`report_${item?.reason_type}`}
                    className={`${
                      item.have_content && reportType === item.type
                        ? 'mb-2'
                        : 'mb-3'
                    }`}>
                    <FormCheck>
                      <FormCheck.Input
                        id={item.reason_type}
                        type="radio"
                        checked={reportType.type === item.reason_type}
                        onChange={() => handleRadio(item)}
                        isInvalid={isInvalid}
                      />
                      <FormCheck.Label htmlFor={item.reason_type}>
                        <span className="fw-bold">{item?.name}</span>
                        <br />
                        <span className="text-secondary">
                          {item?.description}
                        </span>
                      </FormCheck.Label>
                      <Form.Control.Feedback type="invalid">
                        {t('msg.empty')}
                      </Form.Control.Feedback>
                    </FormCheck>
                  </Form.Group>
                  {reportType.haveContent &&
                    reportType.type === item.reason_type && (
                      <Form.Group controlId="content" className="ps-4 mb-3">
                        <Form.Control
                          type="text"
                          as={
                            item.content_type === 'text' ? 'input' : 'textarea'
                          }
                          value={content.value}
                          isInvalid={content.isInvalid}
                          placeholder={item.placeholder}
                          onChange={(e) =>
                            setContent({
                              value: e.target.value,
                              isInvalid: false,
                              errorMsg: '',
                            })
                          }
                        />
                        <Form.Control.Feedback type="invalid">
                          {content.errorMsg}
                        </Form.Control.Feedback>
                      </Form.Group>
                    )}
                </div>
              );
            })}
          </Form>
        </Modal.Body>
        <Modal.Footer>
          <Button variant="link" onClick={() => onClose()}>
            {t('btn_cancel')}
          </Button>
          <Button variant="primary" onClick={handleSubmit}>
            {t('btn_submit')}
          </Button>
        </Modal.Footer>
      </Modal>,
    );
  });
  return {
    onClose,
    onShow,
  };
};

export default useReportModal;
